S3 presigned URL expired or generated wrong
Browser upload/download fails with AccessDenied immediately
Focused incident mode — strips away everything but this runbook.
Symptoms
- Browser upload/download fails with AccessDenied immediately
- Presigned links work for seconds then die
- Temporal S3 failures match 'expired in the middle of a big upload'
Evidence to grab
Collect these artifacts before you change anything — they prove (or rule out) each cause.
Reproduce the signing
aws s3 presign s3://<BUCKET>/<KEY> --expires-in <SECONDS>Bucket region
aws s3api get-bucket-location --bucket <BUCKET>
Diagnostic flow
Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.
Guided decision tree is ready.
Steps with commands, expected output, and pass/fail branches.
Ranked root causes
Evidence checklist
- Large file uploads fail midway
- expires-in is seconds-to-minutes by design
Confirm before fixing
aws s3 presign s3://<BUCKET>/<KEY> --expires-in 60Prove the short window on a test object
Fix
aws s3 presign s3://<BUCKET>/<KEY> --expires-in 3600Generate a longer-lived URL for slow clients (then shorten once the client is fixed)
Resolution runbook
Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.
aws s3 presign s3://<BUCKET>/<KEY> --expires-in 900Regenerate with a sane window
aws s3api get-bucket-location --bucket <BUCKET>Confirm region for SigV4
curl -v -I '<PRESIGNED-URL>'Exercise the exact URL from the failing client
Expected: A 200 (or a fresh AccessDenied naming the mismatch)
Prevention
- Size expires-in for the slowest legit client plus a buffer.
- Sign with the bucket's region explicitly, not the default.
- Log presign requests client-side so TTL abuse is visible.
Related runbooks
Same stack, same failure family — worth a skim.
Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.