---
cuppy_hub: aws
cuppy_path: reference/cloudfront/errors.md
cuppy_section: docs
cuppy_doc: PVW8-NAG3
cuppy_doc_uuid: 13bebe67-c1e3-4fdc-bee5-5571195cb8b6
cuppy_permalink: https://cuppy.io/aws/d/PVW8-NAG3
cuppy_version: 4
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/aws/docs/reference/cloudfront/errors
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 91b00130e27a73fab969e83c4055885805982c917322618d4f8b4795173abdeb
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Amazon CloudFront errors

**First decide whether CloudFront itself refused the request or relayed the origin's answer.** Call the origin directly with the same path and `Host` header. If the error reproduces there, the origin produced it. A 502 that CloudFront generates carries `X-Cache: Error from cloudfront`.

## 403 Forbidden

| Cause | Fix | Check |
|---|---|---|
| **DNS points at CloudFront, but the domain isn't an alternate domain name on the distribution** | Add it (the certificate must cover it) | `aws cloudfront get-distribution-config --id <d> --query DistributionConfig.Aliases` |
| **AWS WAF blocked it**, at CloudFront or at the origin | CloudFront can't tell a WAF 403 from an origin 403. Check the web ACL's sampled or blocked requests | `aws cloudfront get-distribution-config --id <d> --query DistributionConfig.WebACLId`, then the ACL's sampled requests (`aws wafv2 get-sampled-requests`) |
| **S3 origin: CloudFront has no access** | Private bucket without OAC/OAI on the origin, or a bucket policy missing the `cloudfront.amazonaws.com` statement with this distribution's `AWS:SourceArn` (`guides/cloudfront/serve-s3-privately.md`). SSE-KMS objects also need the key-policy statement | `aws cloudfront get-distribution-config --id <d> --query DistributionConfig.Origins` → `OriginAccessControlId`; `aws s3api get-bucket-policy --bucket <b>` |
| **S3 origin: wrong path or missing object** | Without `s3:ListBucket`, S3 returns 403 instead of 404 for a missing key. A default root object or index document applies at the root only (UNVERIFIED in the collected sources) | `aws s3api head-object --bucket <b> --key <key>` with the origin path prepended |
| **S3 origin: Host header forwarded** | Don't forward the viewer's `Host` to an S3 REST endpoint (use an origin request policy that excludes it) | `aws cloudfront get-origin-request-policy --id <id>` → headers forwarded |
| **Custom error pages** configured | The error page itself may be missing or forbidden | `aws cloudfront get-distribution-config --id <d> --query DistributionConfig.CustomErrorResponses` |
| **Custom origin firewall** | The origin rejects CloudFront. Reproduce directly, then read the origin's logs | `curl -sI https://<origin>/<path>` from outside AWS, then the origin's logs |
| **Geographic restriction** | The viewer's country is blocked by design | `aws cloudfront get-distribution-config --id <d> --query DistributionConfig.Restrictions` |
| **Restrict viewer access** on the behaviour | The request lacks a valid signed URL or signed cookie | `aws cloudfront get-distribution-config --id <d> --query DistributionConfig.DefaultCacheBehavior.TrustedKeyGroups` (and each `CacheBehaviors` entry) |
| **Stacked distributions** (a distribution whose origin is another distribution) | Not supported: returns 403 | `aws cloudfront get-distribution-config --id <d> --query DistributionConfig.Origins`: a `*.cloudfront.net` domain |

## 502 Bad Gateway: couldn't use the origin

| Cause | Fix | Check |
|---|---|---|
| **Origin certificate doesn't match** the origin domain name, or the `Host` header sent | Reissue the certificate with the right names, or change the origin domain | `openssl s_client -connect <origin>:443 -servername <name>`: subject and SANs |
| **Origin certificate expired, invalid or self-signed, or the chain is incomplete or in the wrong order** | Install the full chain from a CA on Mozilla's trusted list, intermediates included | `openssl s_client -connect <origin>:443 -servername <name> -showcerts`: `Verify return code` |
| **No common cipher or protocol** with CloudFront | Compare the origin's TLS configuration with CloudFront's supported origin ciphers | `openssl s_client -connect <origin>:443 -tls1_2` (and `-tls1_3`) |
| **Origin not listening on the configured ports** (defaults 80/443), or a firewall blocks CloudFront's IP ranges | Allow the CloudFront origin-facing prefix list `com.amazonaws.global.cloudfront.origin-facing` (also `com.amazonaws.global.ipv6.cloudfront.origin-facing` for IPv6) in the origin's security group | `aws ec2 describe-security-group-rules --filters Name=group-id,Values=<sg>`: is the prefix list there? |
| **`NonS3OriginDnsError`** | CloudFront couldn't resolve the origin name in **public** DNS. Fix the NS/SOA records | `dig <apex> NS +short`, then query each name server, from the internet |
| **Lambda@Edge returned an invalid response** | Fix the function's response shape | The function's logs in the Region nearest the viewer (`/aws/lambda/us-east-1.<fn>`) |
| **A CloudFront Function changed a read-only header** | Only shows after deployment, not in the test console | `aws cloudfront test-function --name <fn> --if-match <etag> --event-object fileb://event.json` |
| **ALB or API Gateway origin returned 502 itself** | `guides/elb/fix-alb-5xx.md` | `curl -sI` the origin directly: a 502 without CloudFront is the origin's |

## 504 Gateway Timeout: the origin didn't answer in time

Check access before performance:

1. **A firewall or security group blocks CloudFront.** Allow the origin-facing prefix list, and keep IP allow-lists current. AWS publishes IP range changes on an SNS topic.
2. **The origin isn't reachable from the internet.** A private server, or an internal load balancer used as an ordinary custom origin, can't be reached. Use a **VPC origin** for private ALBs, NLBs and EC2 instances (`patterns/cloudfront-to-alb.md`). The 504 page's statement that private servers can't be origins predates VPC origins.
3. **The origin is slow.** Measure with `curl -w` (time to first byte), add capacity, tune queries, and enable keep-alive. Then, if needed, raise the distribution's **origin response timeout**.
4. **The origin's own timeouts.** ALB origins: a 10 s connect timeout, the idle timeout, the NACL ephemeral return path, `Content-Length` larger than the body. API Gateway: the integration timeout.

Test: `nc -zv <origin-domain> 443` from the internet.

## VPC origin–specific

| Symptom | Fix | Check |
|---|---|---|
| VPC origin can't be created | The VPC needs an internet gateway attached (it isn't used for routing) and a free IP in the private subnet. Gateway Load Balancers and NLBs with TLS listeners aren't supported, and an NLB needs a security group | `aws ec2 describe-internet-gateways --filters Name=attachment.vpc-id,Values=<vpc>` |
| Timeouts to a VPC origin | The origin's security group must allow the origin-facing prefix list or the `CloudFront-VPCOrigins-Service-SG` group. The **outbound** NACL must allow ephemeral ports 1024–65535 for return traffic (inbound NACLs aren't evaluated) | `aws ec2 describe-security-group-rules --filters Name=group-id,Values=<sg>` |
| gRPC or Lambda@Edge origin triggers fail | Not supported with VPC origins | `DefaultCacheBehavior.GrpcConfig` and `LambdaFunctionAssociations` on the VPC-origin behaviour |

## 400, 412, 500, 503

| Status | Cause → fix | Check |
|---|---|---|
| **400** with `The authorization header is malformed; the region '<r1>' is wrong; expecting '<r2>'` | The S3 bucket was deleted and recreated with the same name in another Region. Edit the origin and save it unchanged ("Yes, Edit") to redeploy | `aws s3api get-bucket-location --bucket <b>` vs the Region in the message |
| **400** from an ALB origin | Malformed request; header limits (16 KB line, 16 KB header, 64 KB total); client closed early | The ALB access log's `elb_status_code` and `request` for that request |
| **412** | A conditional non-GET/HEAD request whose `If-Unmodified-Since`/`If-None-Match` failed; or a condition in an `UpdateDistribution` call evaluated false (a stale `IfMatch` ETag, UNVERIFIED example) | Replay the request with and without its conditional headers |
| **500** | Usually the origin's own 500 (S3, API Gateway, ELB). Otherwise an edge (PoP) error: contact Support | `X-Cache` and `x-amz-cf-pop` response headers; the origin's logs at that time |
| **503** | Origin capacity. For S3: 3,500 write and 5,500 read requests per second **per prefix** → spread keys across prefixes. Or unhealthy or overloaded ELB targets, an origin out of CPU or memory, an API Gateway backend. Rarely, edge capacity (common in load tests: follow CloudFront's load-testing guidance). Also a Lambda@Edge or CloudFront Function execution error, Lambda@Edge throttling or timeout, or an origin mTLS handshake failing repeatedly (temporary) | S3 `5xxErrors` request metrics, or the origin's own capacity metrics |

## Certificate errors at the viewer

- **Certificate not selectable on the distribution**: it isn't in ACM **us-east-1**.
- **Alternate domain name rejected**: the certificate's SAN doesn't cover it.
- **An imported certificate expiring**: re-import at least 24 hours before `NotAfter`; propagation can take up to 24 hours.

## When none of these fits

Capture the response's `x-amz-cf-id` and `x-cache` headers and the time. Then test the origin directly, bypassing CloudFront. If the origin fails too, it's an origin problem (`reference/elb/errors.md`, `reference/s3/bucket-and-object-errors.md`); if not, compare the cache and origin request policies with what the origin needs. Standard logs for the distribution show the result type per request. AWS Support can trace a request by its `x-amz-cf-id` (UNVERIFIED).


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 131 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/aws/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
