S3 RequestTimeTooSkewed: Fix the Clock That Signed It
The S3 error RequestTimeTooSkewed means the clock on the machine that signed your request is more than 15 minutes away from S3's own clock, ahead or behind, so the fix is to put that machine on automatic time and send the request again. Here's the twist: 15 minutes is a wide gap, wider than the five minutes that applies to most AWS services, so a clock that merely looks a little off on your screen is rarely the culprit. The clock that counts is the one inside the shell, virtual machine, container or server that actually sent the request.
Jake's nightly backup of the day's repair photos, into a bucket named after a cat called Biscuit who has since retired, stopped landing on a Tuesday. He found out on Friday, when a customer disputed a $180 screen-repair warranty claim and the "before" photo Jake had promised to have on file wasn't there. The backup script's log had been saying the same thing three nights running: An error occurred (RequestTimeTooSkewed) when calling the PutObject operation: The difference between the request time and the current time is too large.
Ethan read it over his shoulder. "It's a clock, Jake. Every request you send to S3 carries a timestamp, and S3 compares that stamp with its own clock. Think of a movie ticket printed with the time. If the stamp is more than 15 minutes off from the theater's clock, the usher turns you away. Not because he thinks you're a thief, but because he can't tell your ticket from an old one somebody kept in a pocket."
The exact RequestTimeTooSkewed error text, and every costume it wears
People search for this error in a dozen different shapes, because every tool wraps it differently. Underneath the wrapping it is always the same thing: the error code is RequestTimeTooSkewed, the HTTP status is 403 Forbidden, and the description S3 publishes reads "The difference between the request time and the server's time is too large." The message S3 puts in the response body is worded slightly differently: The difference between the request time and the current time is too large. Same error, two phrasings.
Here is the shape of the XML that comes back. The three lines in the middle are the whole diagnosis, so it's worth learning to read them.
<Error>
<Code>RequestTimeTooSkewed</Code>
<Message>The difference between the request time and the current time is too large.</Message>
<RequestTime>20150604T232559Z</RequestTime>
<ServerTime>2015-06-04T22:26:16Z</ServerTime>
<MaxAllowedSkewMilliseconds>900000</MaxAllowedSkewMilliseconds>
<RequestId>...</RequestId>
<HostId>...</HostId>
</Error>
RequestTime is the timestamp your machine stamped on the request, in UTC (Coordinated Universal Time, the world's reference clock that has no time zone or daylight-saving changes). ServerTime is what S3's clock said when the request arrived. MaxAllowedSkewMilliseconds is the limit: 900,000 milliseconds, which is 900 seconds, which is 15 minutes. In the sample above, the request claims 23:25:59 while S3 says 22:26:16, a gap of 59 minutes and 43 seconds, close to a round hour, which looks more like a time-zone slip than slow drift. One quirk: RequestTime doesn't always use that compact format. Older clients that sign with the HTTP Date header produce responses where it reads like Mon, 18 Jan 2016 14:51:35 GMT. Same field, same subtraction.
| Where you see it | How it reads | What to copy out |
|---|---|---|
| AWS CLI | An error occurred (RequestTimeTooSkewed) when calling the CreateMultipartUpload operation: The difference between the request time and the current time is too large. |
Run again with --debug to get the two times and the request IDs |
| Python (boto3) | botocore.exceptions.ClientError: An error occurred (RequestTimeTooSkewed) when calling the ListBuckets operation |
The error code inside the exception's response |
| PHP SDK | Aws\S3\Exception\S3Exception ... Client error: 403 RequestTimeTooSkewed (client) |
The XML body, which carries RequestTime and ServerTime |
| Ruby SDK | Aws::S3::Errors::RequestTimeTooSkewed |
The exception message plus request ID |
| Java SDK v2 | S3Exception whose error code is RequestTimeTooSkewed |
The status code, error code and extended request ID |
| Backup and sync software | The same words inside the vendor's own wrapper, often ending in error code: 403 |
Whichever log line names the code, then check the clock on the machine that runs the backup job |
Notice what is missing from that table: the operation name doesn't matter. ListBuckets, PutObject, UploadPart and CreateMultipartUpload (the piece-by-piece upload S3 uses for big files) all fail identically, because the timestamp check isn't about what you asked for. It is about when you asked.
🙋♂️ Jake's Reality Check
"It says 403. Doesn't 403 mean somebody changed my bucket permissions?"
The straight answer. Not this time. S3 files RequestTimeTooSkewed under 403 right next to SignatureDoesNotMatch, InvalidAccessKeyId and AccountProblem, which is why it looks like a permissions problem at a glance. It isn't. Your bucket policy, permissions and keys never got a vote; the request was turned away at the timestamp.
The 15-minute rule, and why AWS's own pages seem to disagree about it
Every request you send to S3 is signed. A signature is a fingerprint computed from your secret access key, the details of the request and the time. The method the CLI and SDKs use is called Signature Version 4, or SigV4. The signed portions of a request are valid within 15 minutes of the timestamp in that request, and S3 compares each request's timestamp with its own clock at the moment the request arrives. The rule exists so that someone who captures a signed request can't replay it later.
The rule is about the difference between two clocks, so it works in both directions. A clock that runs 16 minutes slow fails. A clock that runs 16 minutes fast fails just as hard. Nothing in the rule mentions your Region, your account or which bucket you're touching. It compares your request's timestamp with S3's clock, full stop.
Now the confusing part. For most AWS services, a request must reach AWS within five minutes of its timestamp. For S3 it's 15. Both numbers are current as of October 1, 2026, and they aren't fighting: five minutes is the common rule, and S3 is the more forgiving one. If you're chasing a signature-time failure in some other service, use the smaller number. If you're here because of the S3 error, 15 minutes (900 seconds) is the line.
| Time limit people mix up | Value | Scope | Error you get when you break it |
|---|---|---|---|
| S3 request timestamp window | 15 minutes (900 seconds), ahead or behind | Per request | RequestTimeTooSkewed (403) |
| General SigV4 replay window | Five minutes in most cases | Per request, other AWS services | Messages such as Signature expired or Signature not yet current |
Presigned URL lifetime (X-Amz-Expires) |
1 second up to 604,800 seconds (seven days) | Per URL | AccessDenied with Request has expired |
| Presigned URL made in the S3 console | 1 minute to 12 hours | Per URL | Same as above |
Presigned URL from aws s3 presign |
3,600 seconds (one hour) by default, up to 604,800 with --expires-in |
Per URL | Same as above |
| Time skew that breaks domain logins on Windows | More than five minutes | Per domain-joined instance | Login trouble, not an S3 error at all |
"Don't memorize both numbers," Ethan told Jake. "Remember that S3 forgives 15 minutes, and that nothing in your setup should ever come near using that forgiveness. A healthy machine is off by milliseconds. If yours is off by minutes, something has stopped doing its job."
✅ Why "just change the time zone" is the wrong advice
The signature uses UTC, the same instant everywhere on Earth. Changing your time zone changes how the clock is displayed, not what instant it is, so it can't fix a wrong clock and a wrong zone can't break a right one. Two exceptions, both covered below: a hand-written signer that forgets to convert local time to UTC, and a Windows instance whose time zone was changed and then restarted.
One check that tells you which clock is wrong
Before you touch a setting, measure. It turns "my clock is probably off" into a number. The only trick is doing it in the right place.
- Open a shell on the exact machine that runs the failing command. That means the server, the virtual machine, the container or the laptop where the script actually runs, not the desk you're sitting at and not the machine you connected from.
- Print that machine's time in UTC. On Linux or macOS, run
date -u. On Windows PowerShell, run(Get-Date).ToUniversalTime(). - Ask S3 what time it thinks it is. Run
curl -sI https://s3.amazonaws.com | grep -i '^date'. On Windows, usecurl.exe -sI https://s3.amazonaws.comand look for theDateline. S3 puts the date and time it responded in that header, so any S3 response is a free clock reading, whatever its status code. - Subtract. If the two readings are more than 900 seconds apart, either way round, you've found your error.
- Or skip steps 2 to 4 if you have the error XML: subtract
RequestTimefromServerTime. The answer is already in the response.
If the gap is under 900 seconds and the error persists, you're measuring the wrong machine, which is why the seventh row of the next table exists.
| Cause | How you can tell | Fix |
|---|---|---|
| 1. Automatic time is switched off | Gap is a few minutes to a few hours and keeps growing | Turn on automatic time; see the OS steps |
| 2. The time daemon has no working source | chronyc sources -v shows no line starting with ^* |
Point it at 169.254.169.123 on EC2 or time.aws.com elsewhere |
| 3. The VM was restored, paused or switched time sources | The clock jumped suddenly, forward or back | Force a resync (w32tm /resync /rediscover on Windows, restart chronyd on Linux) |
| 4. Windows instance time zone changed, then restarted | Offset roughly equals the zone difference | Put the instance back on UTC and resync |
| 5. Hand-written signing code treats local time as UTC | Gap is exactly your UTC offset, such as 5 hours 30 minutes or 8 hours | Convert to UTC before formatting X-Amz-Date, or use an SDK |
| 6. The endpoint isn't Amazon's | The host in --debug output doesn't end in amazonaws.com |
You're talking to a look-alike service; check that server's clock and its rules |
| 7. You checked one clock and the signing happens on another | Your desk looks right, the error insists otherwise | Run date -u inside the same shell, VM or container as the failing command |
If I had to bet, I'd bet on rows 1 and 7: switched-off automatic time is the boring default, and modern setups put an extra layer of machine between you and the clock.
🙋♂️ Jake's Reality Check
"Wait. So my computer's clock is a security credential? It can't even keep the shop's opening hours in sync with my phone."
The straight answer. Sort of, yes. The timestamp is part of what proves the request is fresh, so a clock that's wrong by a quarter of an hour invalidates an otherwise perfect set of keys. Automatic time fixes it for good, and it costs nothing.
Fix the clock on Windows, macOS and Linux (the console route)
There is no S3 console setting for this, and no bucket property either, so "console route" here means two things: the date and time screens on the machine that sends the request, and the AWS Management Console as a clean second opinion. For that second opinion, choose the CloudShell icon in the console's top navigation bar, or open https://console.aws.amazon.com/cloudshell/. CloudShell is a browser-based shell that comes signed in with your console credentials and has the AWS CLI already installed. Run the same S3 command there. If it works, your bucket, permissions and keys are fine and the clock on your own machine is the one to fix. That's comforting to know at 11 p.m.
| Machine | Where to change it | Time source to use | How to confirm |
|---|---|---|---|
| Windows PC (not in a domain) | Control Panel → Date and Time → Internet Time tab → Change settings → check Synchronize with an Internet time server | time.aws.com in the Server box |
w32tm /query /status |
| Windows EC2 instance | Command Prompt: w32tm /config /manualpeerlist:169.254.169.123 /syncfromflags:manual /update |
169.254.169.123, which most Amazon Windows AMIs already use |
w32tm /query /configuration, then look at NtpServer |
| macOS | Date & Time settings (System Settings, or System Preferences on older versions) → set date and time automatically | time.aws.com in the source box |
date -u against S3's Date header |
| Linux EC2 instance | /etc/chrony.conf (Ubuntu: /etc/chrony/chrony.conf) |
169.254.169.123 (IPv6: fd00:ec2::123 on Nitro-based instances) |
chronyc sources -v | grep -F ^* and chronyc tracking |
| Linux server outside AWS | Same chrony file, or /etc/ntp.conf if you run ntpd |
pool time.aws.com iburst |
chronyc tracking |
Linux: the steps in order
Chrony is the modern time daemon (a background program whose whole job is keeping the clock honest). NTP, the Network Time Protocol, is the language it speaks to time servers. Amazon Linux 2023 and recent Amazon Linux 2 are already configured to use the Amazon Time Sync Service, so on those you're usually verifying, not configuring.
- See what is syncing. Run
chronyc sources -v | grep -F ^*. The line starting with^*is the source the clock is currently following. If nothing prints, nothing is being followed. - Install chrony if it's missing. On older Amazon Linux 2 it's
sudo yum install chrony(aftersudo yum erase 'ntp*'to remove the old daemon). On Ubuntu it'ssudo apt install chrony. - On EC2, add the local source. Put
server 169.254.169.123 prefer iburst minpoll 4 maxpoll 4before any otherserverorpoollines in the chrony config file. - Off AWS, add the public source. Add
pool time.aws.com iburst, then runsudo service chronyd force-reload. On an EC2 instance, keep the local line and use the public pool only as a backup. - Restart the daemon with
sudo systemctl restart chronyd(on Ubuntu the service is calledchrony). - Check the result with
chronyc tracking. TheSystem timeline says how far the clock sits from NTP time. On a healthy instance that figure is a few millionths of a second. - Rerun the failing S3 command.
Two details save headaches. The 169.254.169.123 address is link-local, meaning it only works from inside your VPC (your private network on AWS), and it needs no internet access, so it works from private subnets with no NAT gateway. time.aws.com does need the internet, which is why it's the backup on EC2 and the main choice everywhere else.
Windows: the paths that work
For an ordinary Windows PC, the Control Panel route in the table above is the one to use. The Internet Time tab isn't available if the PC belongs to a domain, because a domain PC follows the domain controller's clock instead. For a Windows EC2 instance, check first: Amazon Windows AMIs released since August 2018 already use the Amazon Time Sync Service, and they check in with the time server every 900 seconds (1,024 seconds on Windows Server 2025) with the service asked to adjust every 120 seconds.
If a Windows instance's clock is wrong anyway, run w32tm /query /configuration, confirm NtpServer shows 169.254.169.123, and then force a resync with w32tm /resync /rediscover.
⚠️ What this actually breaks
Don't hand-set the clock on a Windows machine that's joined to a domain. A time skew of more than five minutes can break authentication against the domain, and you can lock people out while fixing an S3 problem. On a domain-joined machine, the clock follows the domain's time hierarchy, so change it there.
"Can't I just set the clock by hand and move on?" Jake asked.
"You can, and the error will vanish," Ethan said. "For a while. A hand-set clock is a promise that nothing will ever drift again, and clocks are terrible at keeping promises. Automatic sync is the only fix that stays fixed."
The CLI route: measure, fix, rerun, and read the request IDs
If you live in a terminal, this is the whole loop. Run it on the machine that runs the failing command.
# 1. This machine's clock, in UTC
date -u
# 2. S3's clock (the Date header on any S3 response)
curl -sI https://s3.amazonaws.com | grep -i '^date'
# 3. Which endpoint is the CLI really calling, and what did it send?
aws s3 ls --debug 2>&1 | grep -i -E 'date|x-amz-request-id|x-amz-id-2'
# 4. What is chrony following, and how far off is it?
chronyc sources -v | grep -F ^*
chronyc tracking
Step 3 does double duty. The --debug flag makes the CLI print the HTTP conversation, and that's where the two request IDs (x-amz-request-id and x-amz-id-2) show up. You'll want them if this ends in a support case. It also shows the host the CLI actually called, which answers a question people forget to ask: is this really S3?
After the fix, rerun the same command that failed. If it now succeeds, you're done. If it fails again, look at RequestTime and ServerTime in the new error. Did the gap shrink? Then you moved the right clock but not far enough. Did it stay identical? Then you changed a clock that isn't the one signing the request.
A few edge cases the quick fixes skip:
- It works in the console but fails in the CLI. That points at the machine the CLI runs on. The bucket, the account and the permissions are clearly fine.
- Cross-account buckets, opt-in Regions and organization-managed accounts. Nothing in the timestamp rule cares whose bucket it is. Region and account settings decide what you may do; they don't change what time it is.
- A bare 403 from HeadObject. A HEAD request gets no response body, so when it fails S3 returns only a generic code such as 403 Forbidden. In the CLI that reads
An error occurred (403) when calling the HeadObject operation: Forbidden. A missing permission produces that exact line, and so can a skewed clock, so run the date check before you rewrite a policy. - Temporary credentials. An expired session token produces its own error (
ExpiredToken, an HTTP 400), which is a different problem with a different fix.
You fixed the clock and it still fails: the "still not working" checklist
You synced the clock, the display looks right, and the same error is back. Work through these in order, cheapest first.
- Read the error again. Is it really
RequestTimeTooSkewed? Similar-looking errors have different causes; the table below sorts them. - Compare the two times in the new error. If the gap is unchanged, you fixed a different machine.
- Check that the time daemon is actually running, not merely installed.
chronyc trackingshould answer. If it errors out, the daemon is stopped. - Check where the command runs. Container, virtual machine, scheduled job on another server, CI runner. Run
date -uin that exact place. - Check for a jump. A restore, a resume or a source switch can throw the clock off after you last looked.
- Check for hand-written signing code. If nobody on your team uses an SDK or the CLI, the bug may be in the code, not the clock.
| Error | Status | What it means | Look at |
|---|---|---|---|
RequestTimeTooSkewed |
403 | Request time and S3's time are too far apart | The clock on the sending machine |
SignatureDoesNotMatch |
403 | The signature S3 calculated differs from yours; check your secret access key and signing method | Keys, signing code, proxies that alter headers |
InvalidAccessKeyId |
403 | The access key ID doesn't exist in AWS's records | The key itself, deleted or mistyped |
ExpiredToken |
400 | The provided token has expired | Temporary credentials that need refreshing |
AccessDenied / Request has expired |
403 | A presigned URL was used after its expiration time | Create a fresh URL; see the presigned URL section below |
When you write your own signing code, a wrong timestamp can be one reason the signatures disagree, so a "signature" error can turn out to be a time problem in disguise. With the CLI or an SDK, RequestTimeTooSkewed is specific: it's about time.
Where the wrong clock hides: VMs, containers, restores and quiet servers
The opening paragraph made a claim: the clock that matters is rarely the one you're looking at. Here are the places it actually lives.
Restored and resumed machines. Big forward or backward jumps on a Windows instance have three usual causes: EC2 restored the instance from a snapshot, the Windows time service corrected a large offset, or the instance switched time sources. XenServer VM Tools (formerly Citrix VM Tools) for Windows can also interfere with time synchronization. The lesson is general: after any machine has been restored, paused or migrated, look at its clock before trusting it.
A Windows instance whose time zone was changed. By default, Windows instances use UTC. If you set a different time zone and then restart, the time becomes offset, and the instance can temporarily lose its IP address for hours. Scheduled tasks then run at the wrong moment, and S3 requests get a timestamp from the wrong hour.
Containers and other layers. I can't tell you from the outside how your particular container platform gets its time, and I won't pretend to. What I can tell you is the test: run date -u inside the container, in the same place the failing command runs, and compare it with S3's Date header. That test works whatever the layer.
Quiet servers with no time source. The old PC in the back room, set up once in 2019 and never touched since, is the technological cousin of a fridge clock blinking 12:00 forever. Left without an NTP source, it drifts. That's what pool time.aws.com iburst is for: the public Amazon Time Sync Service at time.aws.com exists for resources outside AWS.
Custom clients with two date headers. A signed S3 request can carry its date in the HTTP Date header or in x-amz-date. If both are present, x-amz-date always wins. So if your own code refreshes one and leaves a stale value in the other, S3 reads the stale one, and the failure looks like a clock problem even though the machine's clock is perfect.
Busy EC2 instances. One more case the usual advice skips. The link-local addresses on EC2 (the ones that only work inside your VPC) share a limit of 1,024 packets per second, and that budget is shared among DNS queries, instance metadata requests, Amazon Time Sync Service NTP requests and, on Windows, licensing requests. An instance that hammers DNS or the metadata service is spending the same budget its clock relies on. If a busy instance has time trouble, check that budget before you blame chrony.
"So which one is Jake's?" Ethan asked, half to himself. Row 1 of the causes table: automatic time was off on the shop PC, and nobody noticed because the display looked plausible. Plausible is the most dangerous kind of wrong.
Presigned URLs: when the wrong clock belongs to whoever made the link
A presigned URL is a link that carries its own signature, so anyone holding it can download or upload one object for a limited time without having AWS credentials of their own. Two of its query parameters matter here. X-Amz-Date is the moment the link was signed, in UTC, written like 20130721T201207Z. X-Amz-Expires is how many seconds the link stays valid; a typical value is 86400, which is 24 hours.
The important point is who wrote that timestamp. It was written by the machine that made the link, not by the customer who clicks it. So for presigned URLs, the clock you have to fix is the signer's: your web server, the backend function that builds invoice links, or the laptop where you ran aws s3 presign. The customer's clock is irrelevant.
Here's the arithmetic of what a slow signing clock does. Suppose your server's clock runs 20 minutes slow. At the true time of 10:00:00 UTC it creates a link with X-Amz-Expires=900 (15 minutes). The link is stamped 09:40:00. Counted from its own stamp, it expires at 09:55:00, which was five minutes before the customer even received it. The customer sees a dead link, and you see "it worked in testing." I can't tell you from the error text alone which timestamp error a given clock mistake will produce, so read the exact code S3 returns before deciding what you're fixing.
| What you see | What it means | What to do |
|---|---|---|
AccessDenied with Request has expired, plus Expires and ServerTime fields in the XML |
The link was used after its expiration time | Create a new link. Compare Expires with ServerTime: a link that was already expired on arrival points at the signer's clock |
RequestTimeTooSkewed on a normal signed request |
The sending machine's clock is more than 900 seconds from S3's | Fix the clock where the request is signed |
| A link that dies before its stated lifetime, yet the clock looks fine | It was made with temporary credentials, and it expires when those credentials do | Make the link with longer-lived credentials, or shorten your expectations |
Beyond the limits in the earlier table, remember that a link made with temporary credentials expires when those credentials expire, even if you asked for a later time. A link also stops working if the credentials that signed it are revoked, deleted or deactivated.
The same UTC rule applies to anyone writing their own signer. A local time of 08/01/2016 15:32:41.982-700, for example, must first be converted to UTC and submitted as 20160801T223241Z. Forget that step and your links are wrong by exactly your offset from UTC. Jake's invoice links, generated by a small script for the booking page, would be off by exactly his time zone's distance from UTC: 5 hours 30 minutes on India Standard Time, 8 hours on Singapore time. Round-number gaps like that are the signature of a forgotten conversion, not a drifting clock.
🙋♂️ Jake's Reality Check
"A customer said the invoice link in her text message was dead the moment it arrived. Is that the same clock thing?"
The straight answer. It can be. A link that's expired on arrival is the classic sign of a signer whose clock runs slow. But an expiry that's too short, or temporary credentials that ran out, look identical to the customer. Check the signer's clock first, then the lifetime, then the credentials.
Which SDKs fix a skewed clock on their own, and why that can mislead you
An SDK is the library your code uses to talk to AWS, and several of them deal with clock skew for you. They notice the error, work out how far off the local clock is from the server's response, and retry with a corrected timestamp. This is a kindness with a catch: it can hide the problem while it's still there.
| SDK or tool | Clock skew behavior | What that means for you |
|---|---|---|
| JavaScript SDK v3 | Always applies clock skew correction. The v2 setting correctClockSkew is deprecated because v3 does it unconditionally |
A Node app may succeed while a shell script on the same box fails |
| JavaScript SDK v2 | Has a correctClockSkew option that applies a correction and retries |
Check whether it's switched on before relying on it |
| .NET SDK | Detects a skew error, calculates the offset, retries with the right time, and stores the offset in AWSConfigs.ClockOffset. A CorrectForClockSkew property can turn it off |
If someone disabled it, you'll see the raw error |
| Java SDK v2 | Ships ClockSkew and RetryUtils.isClockSkewException helpers used in its retry logic |
Clock skew is treated as its own class of retryable error |
| Java SDK v1 | The default retry condition retries clock skew errors along with 500s, 503s and throttling | Same caveat: correct in code, wrong on the machine |
| AWS CLI and Python (boto3) | You see the error in real bug reports, including CreateMultipartUpload failures from aws s3 cp --recursive. A feature request for skew correction in boto3 has existed since 2017 |
Don't wait for a code fix; fix the clock |
If one program on a machine works and another fails with this error, one possible reason is that one of them quietly corrects for the skew and the other doesn't. The working program hasn't proven the clock is fine. A bug report in the .NET SDK's GitHub repository adds a subtlety: correction that retries on every skew-type error can waste time when the real problem was something else, which is one more reason to read the code S3 returned.
Ethan's rule of thumb: "Treat SDK correction like a spare tire. It gets you home. It doesn't mean the car is fine."
What it costs: $0.00 per failed call, and how fast a drifting clock gets there
The good news first. In general, S3 bucket owners are billed for requests that succeed and for requests that fail with an HTTP 4XX client error. But the list of specific error codes that aren't billed includes RequestTimeTooSkewed, which sits in the 403 group alongside SignatureDoesNotMatch and InvalidAccessKeyId. So in US East (N. Virginia), the request charges for every failed call in this story are $0.00, however many times your script retries. That's the current list as of October 1, 2026. The Amazon Time Sync Service itself has no additional charge either.
The bad news is that "no charge" is not the same as "no cost." The cost here is the work that quietly didn't happen. Jake's script failed on three nights and nobody was told. The actual bill was one disputed $180 warranty claim, a missing photo and a very unpleasant Friday.
| Reading (worked example) | Value | Arithmetic |
|---|---|---|
| S3's clock when the backup starts | 02:00:00 UTC | The reference |
| Jake's shop PC says | 01:38:00 UTC | 22 minutes behind = 1,320 seconds |
| Allowed skew | 900 seconds | 1,320 − 900 = 420 seconds (7 minutes) over |
| Earliest reading that would pass | 01:45:00 UTC | 02:00:00 − 15 minutes |
| Request charges for the failed uploads | $0.00 | The error code is on the not-billed list |
A clock doesn't usually break in one step; it drifts. This table is hypothetical arithmetic, not a claim about any real machine. Each row is 900 seconds divided by the drift per day.
| If a clock drifts by | It crosses 900 seconds after | What that feels like |
|---|---|---|
| 5 seconds a day | 180 days | Works for six months, then stops on a random Tuesday |
| 30 seconds a day | 30 days | Breaks about a month after the last reboot or sync |
| 2 minutes a day | 7.5 days (7 days 12 hours) | Breaks weekly and looks intermittent |
| 10 minutes a day | 1.5 days (36 hours) | Obvious within two days |
The slow rows are the treacherous ones: a clock that's fine for six months and then fails looks like an AWS problem, because nothing on your side visibly changed.
Automate the check so this can't sneak up again
If you run a scheduled job that talks to S3, give it a pre-flight check: compare the machine's clock with S3's, and refuse to run (loudly) if they disagree by more than 10 minutes. That leaves five minutes of headroom under the real limit, so you find out about drift before S3 tells you.
#!/usr/bin/env bash
# Abort the backup if this machine's clock is more than 10 minutes from S3's.
s3_date=$(curl -sI https://s3.amazonaws.com | tr -d '\r' | awk -F': ' 'tolower($1)=="date" {print $2}')
s3_epoch=$(date -u -d "$s3_date" +%s)
now_epoch=$(date -u +%s)
skew=$(( now_epoch - s3_epoch ))
abs=${skew#-}
if [ "$abs" -gt 600 ]; then
echo "Clock is ${skew}s away from S3 - not running the backup" >&2
exit 1
fi
aws s3 sync /shop/photos s3://your-bucket/photos
The date -d form is GNU date, the one on most Linux systems; macOS's date takes different flags. A positive skew means your clock is ahead of S3's, and a negative one means it's behind. Wire the exit 1 to something that tells a human: an email, a chat message, an alarm. A silent failure was the whole problem.
A nightly log of chronyc tracking on Linux, or w32tm /query /status on Windows, leaves a drift trail. The first sign of a bad clock should be a line in a log, not a Friday afternoon.
What changed lately in AWS time sync, and why you don't need it for this
🕐 What changed between versions
- Before: microsecond-accurate time without a placement group was limited to a handful of Regions (US East N. Virginia and Ohio, Asia Pacific Malaysia, Thailand and Tokyo, Europe Stockholm) and a few instance families.
- Now: on June 30, 2026, Amazon Time Sync Service added microsecond-accurate time on 26 additional EC2 instance types in all commercial Regions, through a precision time placement group (a placement group created with the
precision-timestrategy). Precision time placement groups cost nothing extra and support newer instance families such as M7, M8, C7, C8, R7, R8, X8g and I8g. - What that means here: nothing. The S3 window is still 15 minutes as of October 1, 2026, and the ordinary NTP source on every EC2 instance is far more accurate than that already.
Microsecond clocks matter when you're ordering events across machines or measuring one-way network latency. Your S3 error tolerates 900 seconds, which is 900,000,000 microseconds. You don't need better hardware. You need the clock you already have to be switched on and pointed at a time source.
When nothing works: what to gather before you open a support case
If you've synced the clock, run the check in the right place, and the error still won't budge, it's time to ask AWS. You'll get further, faster, with the right evidence in the first message. Whenever you contact AWS Support about an S3 error, you must provide the request IDs for the failed action. They come in a pair and are returned in every S3 response, including error responses.
- The full error. The complete XML or SDK message, including
RequestTime,ServerTimeandMaxAllowedSkewMilliseconds. - Both request IDs.
x-amz-request-idandx-amz-id-2. The CLI prints them when you add--debug. SDK errors show them as the request ID and the S3 extended request ID. You can also recover them from CloudTrail data events, S3 server access logs or a browser's developer tools. - The exact time of failure in UTC, plus the output of
date -utaken at the same moment on the sending machine. - The time-sync evidence.
chronyc trackingandchronyc sources -von Linux, orw32tm /query /statusandw32tm /query /configurationon Windows. - The endpoint and the tool. The host from your
--debugoutput, the Region, the CLI or SDK and its version. - Whether the same command works in CloudShell. That single line tells Support whether to look at your machine or at your account.
Now the honest part: what Support can and can't do. With the request IDs, AWS can look at what happened to a specific request on its side. What Support can't do is set the clock on your laptop, your VM or your on-premises server, and it can't help if the endpoint you're calling isn't Amazon's. If the clock on your machine is 40 minutes off and you can't or won't fix it, the answer is not a support case. It's the clock.
RequestTimeTooSkewed FAQ: the questions people actually type
What does RequestTimeTooSkewed mean in Amazon S3?
It means the timestamp on your request and S3's own clock are more than 15 minutes apart, in either direction. S3 returns it as HTTP 403 Forbidden, but it's a clock problem, not a permissions problem. The fix is on the machine that signed the request: put it on automatic time and send the request again.
How much clock skew does S3 allow before it rejects a request?
As of October 1, 2026, S3 accepts a request whose timestamp is within 15 minutes (900 seconds) of its own clock. The error's MaxAllowedSkewMilliseconds field shows it as 900000. Most other AWS services use five minutes, so don't confuse the two.
Why do I get "The difference between the request time and the current time is too large"?
That sentence is the message text of RequestTimeTooSkewed. Subtract RequestTime from ServerTime in the error XML. If the gap is over 900 seconds, the sending machine's clock is wrong, or hand-written signing code is mishandling UTC. A gap equal to your time zone's UTC offset points at the second cause.
How do I fix RequestTimeTooSkewed in the AWS CLI?
The CLI isn't the problem; the clock on the machine running it is. Compare date -u with the Date header from curl -sI https://s3.amazonaws.com. Turn on automatic time, or point chrony at time.aws.com (or 169.254.169.123 on EC2), then rerun the command. Add --debug if you need the request IDs.
Why is RequestTimeTooSkewed still happening after I synced my clock?
Usually one of three things: you fixed a different machine than the one that signs the request, the time daemon isn't actually running, or something jumped the clock afterward, such as a restore, a resume or a time-source switch. Compare RequestTime and ServerTime in the new error. An unchanged gap means you changed the wrong clock.
Can RequestTimeTooSkewed happen if my clock is ahead, not behind?
Yes. The rule is about the difference between the two clocks, so a clock 16 minutes fast fails exactly like one 16 minutes slow. In the Java SDK's convention, a positive skew means a fast client clock and a negative one a slow clock; beyond 900 seconds, either sign triggers the error.
How do I fix RequestTimeTooSkewed on an EC2 instance?
Point the instance at the Amazon Time Sync Service at 169.254.169.123. Amazon Linux 2023 and recent Amazon Linux 2 already use it; confirm with chronyc sources -v | grep -F ^*. Windows AMIs released since August 2018 use it by default; confirm with w32tm /query /configuration. You don't need a precision time placement group for this error.
How do I fix RequestTimeTooSkewed on Windows?
On a regular PC, open Control Panel, choose Date and Time, open the Internet Time tab, choose Change settings, check Synchronize with an Internet time server, and enter time.aws.com. On a domain-joined machine, fix the time through the domain instead. On a Windows EC2 instance, use the w32tm commands shown above, then w32tm /resync /rediscover.
Why does RequestTimeTooSkewed only happen inside Docker or a virtual machine?
Because the clock that signs the request lives inside that environment, and it can differ from the one on your desk. Run date -u in the same place the command runs and compare it with S3's Date header. Restores, pauses, migrations and time-source switches are known causes of big clock jumps. I can't say how your particular platform gets its time.
Is RequestTimeTooSkewed the same as SignatureDoesNotMatch?
No. Both come back as HTTP 403. RequestTimeTooSkewed means the clocks are too far apart. SignatureDoesNotMatch means the signature S3 calculated differs from yours, so check the secret access key and the signing method. Hand-written signing code can trigger either, so prefer an SDK or the CLI.
What is the difference between RequestTimeTooSkewed and "Request has expired" on a presigned URL?
"Request has expired" is an AccessDenied response for a presigned URL used after its expiration; the fix is a fresh link. RequestTimeTooSkewed means the sending clock is more than 900 seconds from S3's. They're linked because a slow clock on the machine that made the link can produce a link that is expired on arrival.
Why does RequestTimeTooSkewed show up halfway through a big upload?
S3 compares each request's timestamp with its own clock when that request arrives, and a multipart upload is many requests. If the machine's clock moved partway through the run, the later requests fail even though the early ones succeeded. Fix the clock and start the upload again.
Do failed RequestTimeTooSkewed requests cost anything?
No request charges. RequestTimeTooSkewed is on S3's list of 403 errors that aren't billed, so the failed calls cost $0.00 in US East (N. Virginia), however many times a script retries. The real cost is the job that never ran.
Does the AWS SDK correct clock skew automatically?
Some do. JavaScript SDK v3 always applies a correction, the .NET SDK computes an offset and retries, and the Java SDKs treat clock skew as a retryable error. The CLI and boto3 have surfaced the raw error in real bug reports. Correction only hides the problem; the clock is still wrong.
Why does head-object return a plain 403 Forbidden instead of RequestTimeTooSkewed?
A HEAD request gets no response body, so when it fails S3 returns only a generic code such as 400, 403 or 404, with no named error to read. A comment in the AWS SDK for .NET source says the same happens for clock skew. If the CLI prints An error occurred (403) when calling the HeadObject operation: Forbidden, run the clock check before you rewrite a bucket policy.
Can I use time.aws.com to sync a machine outside AWS?
Yes. The public Amazon Time Sync Service at time.aws.com is meant for internet-connected devices such as laptops and on-premises servers. On Linux, add pool time.aws.com iburst to your chrony config. On EC2, keep the local 169.254.169.123 line as the main source.
Jake's backup script now checks the clock before it does anything else, and Biscuit's bucket has never looked so well tended. If you've hit a case this page doesn't cover, or one of my numbers has gone stale by the time you read this, I'd rather be corrected than be quietly wrong. In the meantime, measure the gap first, fix the clock where the request is actually signed, and let automatic time do the boring work it was built for.
📌 If you keep one line from this page
S3 forgives a 15-minute gap between its clock and yours, so if you get RequestTimeTooSkewed, measure the gap on the machine that signed the request, then put that machine on automatic time.
The fix is a time source, not a permission.
Revision note. Written October 1, 2026, after one too many backups died over a few minutes of drift. Fix the clock once, add the guard, and let the log do the worrying.