Error reference
What you are seeing, why it happens here, and the fix.
Refused before it started
Anything in this group means the request was rejected at the edge — it never reached storage.
| Error | Why | Fix |
|---|---|---|
| SignatureDoesNotMatch403 | The signature does not cover the request that arrived. Almost always one of: the secret is wrong, a proxy rewrote a header after signing, or the key contains . or .. path segments. | Check the secret first. If it is right, see dot-segment keys — that one is ours, not yours. |
| InvalidAccessKeyId403“The access key id you provided does not exist in our records.” | No credential with that id. Either it was revoked, or the request went to a different environment than the one the credential belongs to. | Confirm the key in the dashboard, and confirm the endpoint host matches it. |
| AccessDenied403“This access key has expired.” | The credential had an expiry and it has passed. | Create a new credential, or one without an expiry for long-lived services. |
| AccessDenied403“Access to this bucket is denied.” | The credential is valid but its scope does not cover this request: the bucket is not in its allowlist, the method is outside its permissions, or the bucket belongs to another organisation. | Check the credential’s scope in the dashboard — see credentials & scopes. A read-only credential returns this for every write. |
| AccessDenied403“The presigned URL has expired.” | The URL’s lifetime elapsed. Signed URLs cannot outlive 7 days. | Sign a new one. For long-lived public assets, use a public bucket instead. |
| AccountProblem403“There is a problem with your account that prevents this operation from completing successfully.” | Your organization’s account is suspended, so every S3 request is refused — signed, presigned and public-bucket reads alike. Your stored data is not deleted. | Sign in to the dashboard to see why, or contact support. The credential itself is fine; retrying or issuing a new key will not change the result. |
| RequestTimeTooSkewed403 | The signing clock is more than fifteen minutes from ours. | Fix the clock on the client — this is nearly always a container without NTP. |
| AccessDenied403“The request signature is incomplete.” | The Authorization header was present but malformed, or a required part was missing. | Use a real SDK rather than hand-rolled signing. If you are signing by hand, the service name is s3 and the signature is v4. |
Wrong shape of request
| Error | Why | Fix |
|---|---|---|
| NoSuchBucket404“The specified bucket does not exist.” | No bucket by that name, or the endpoint/DNS for a virtual-hosted bucket name is not configured for the client. | Verify the bucket name and credential scope. If the bucket name contains dots, use path-style addressing; otherwise verify that the endpoint certificate covers the virtual-hosted bucket hostname. |
| MethodNotAllowed405 | A bucket-level write: creating or deleting a bucket, or setting a policy, lifecycle rule, website configuration, CORS rule or replication rule. | Buckets and their configuration belong to the control plane. Create buckets in the dashboard, and set CORS with PUT /v1/buckets/{bucket}/cors. See buckets and CORS. |
| NotImplemented501 | An upload using per-chunk signed streaming (STREAMING-AWS4-HMAC-SHA256-PAYLOAD), a non-STANDARD storage class, or an operation we do not offer. | On a current SDK this does not happen — the modern default streaming mode works. See signed streaming. |
| InvalidRequest400 | A conditional read: If-None-Match, If-Match or If-Modified-Since on a GET. | Do not send conditional headers on reads for now — see conditional reads. If a CDN in front of a bucket is sending them, cache on a fixed TTL and version your keys. |
| EntityTooSmall400 | A multipart upload whose non-final part was under 5 MiB. | Raise the part size. Every SDK’s uploader defaults above this already. |
| BadDigest400 | The checksum sent with the object did not match its bytes. | Usually a truncated or mutated body in transit. Retry; if it persists, the source is changing under you. |
A response that is not XML at all
Every error we produce is an S3 error document. If you receive HTML — a challenge page, or something that will not parse — the request was stopped in front of the endpoint by bot protection, usually because the client sent no recognisable user agent. See unusual user agents. Use a real SDK, or set a descriptive User-Agent.
A browser upload that fails before it starts
If the browser console shows a CORS error and the network tab shows a failed OPTIONS, the bucket has no rule for your origin. This looks exactly like a signing failure from the browser side, and it is not. Add your origin with PUT /v1/buckets/{bucket}/cors — see browser uploads.