How to fix RequestTimeTooSkewed in AWS S3
What the error means
AWS rejects a signed request with RequestTimeTooSkewed when the time in the request is too far from AWS's own clock. For S3 the allowed gap is 15 minutes. The request time comes from the X-Amz-Date header or query parameter, which your SDK fills in from your machine's clock.
So this error almost always means your clock is wrong. Your credentials and your code are fine.
The error XML shows both times:
`xml
<Error>
<Code>RequestTimeTooSkewed</Code>
<Message>The difference between the request time and the current time is too large.</Message>
<RequestTime>20261016T091502Z</RequestTime>
<ServerTime>2026-10-16T09:47:11Z</ServerTime>
<MaxAllowedSkewMilliseconds>900000</MaxAllowedSkewMilliseconds>
</Error>
`
Subtract one from the other and you know how far off you are.
Step 1: Check the clock
Compare your clock in UTC with a trusted source.
- Linux / macOS:
date -u - Windows (PowerShell):
(Get-Date).ToUniversalTime() - Ask a server for its time:
curl -sI https://s3.amazonaws.com | grep -i '^date'
If the difference is minutes or hours, you've found the cause.
Step 2: Fix the clock for your environment
Linux servers and EC2
- Check sync status with
timedatectl status. Look forSystem clock synchronized: yes. - Turn on NTP:
sudo timedatectl set-ntp true, or install and enablechrony. - On EC2, you can point chrony at the Amazon Time Sync Service (
169.254.169.123).
Windows
- Settings → Time & language → Date & time → "Sync now".
- Or from an admin shell:
w32tm /resync.
macOS
- System Settings → General → Date & Time → turn on "Set time and date automatically".
Docker and WSL
Containers use the host's clock, so fix the host. WSL 2 and Docker Desktop VMs can drift after the laptop sleeps. Restarting the VM (wsl --shutdown, or restarting Docker Desktop) usually brings the clock back in line.
Virtual machines in general
VMs that are suspended and resumed often wake up with an old clock. Turn on guest time sync or run NTP inside the VM.
Step 3: Check for a timezone bug in your own code
If the clock is right but the error persists, look at how the timestamp is made:
X-Amz-Datemust be UTC in the formatYYYYMMDDTHHMMSSZ. Local time with aZstuck on the end will be off by your UTC offset. An error that's off by exactly a whole number of hours points to this.- If you sign requests by hand, make sure the date in the credential scope (
YYYYMMDD) uses the same UTC date asX-Amz-Date.
Step 4: Check for stale or replayed requests
The 15-minute window counts from when the request was signed. You can hit this error with a correct clock if a signed request is sent too late. That happens with:
- Retry queues that resend an already-signed request after a long delay.
- Requests built in a batch and sent much later.
Sign each request right before you send it.
Presigned URLs work differently
A presigned URL is meant to be used later, so the 15-minute rule doesn't apply in the same way. Its lifetime comes from X-Amz-Expires. When it runs out you get a different error (Request has expired). A wrong clock on the machine that creates the URL still matters, though. A URL created by a server that's an hour behind will expire an hour earlier than you expect, or may already be expired when it's made.
Quick checklist
- [ ] Compare
RequestTimeandServerTimein the error - [ ] Clock synced with NTP on the machine that signs
- [ ] Timestamp generated in UTC
- [ ] Request signed right before it's sent, not queued
Getting a plain-words explanation
If you'd rather not decode the XML by hand: we make Presign Pad, a free browser tool. Paste the error and it explains RequestTimeTooSkewed, ExpiredToken, AccessDenied and similar errors in plain words, next to the request it signed.