---
cuppy_hub: aws
cuppy_path: guides/elb/fix-alb-5xx.md
cuppy_section: docs
cuppy_doc: 3TNR-J9EE
cuppy_doc_uuid: 5fcc0790-5651-4dc1-bf7a-80ac8a3756e9
cuppy_permalink: https://cuppy.io/aws/d/3TNR-J9EE
cuppy_version: 4
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/aws/docs/guides/elb/fix-alb-5xx
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: eed416d9c94b554bbfb49b3734b3624bbb24342ea83cafac9729e2048d93f834
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Fix 502, 503 and 504 from an Application Load Balancer

**First find out who produced the status.** The load balancer forwards a target's own 5xx unchanged. Those are application bugs. The 502, 503 and 504 that the load balancer **generates** mean it could not get a usable answer from a target. Only those are covered here.

## Step 0: load balancer or target?

| Evidence | Load balancer generated | Target generated |
|---|---|---|
| Access log `elb_status_code` / `target_status_code` | `502` / `-` | `502` / `502` |
| Metric | `HTTPCode_ELB_5XX_Count` (`HTTPCode_ELB_502_Count`…) | `HTTPCode_Target_5XX_Count` |

A target-generated error belongs to the application: read its logs. Turn on access logs if they are off (load balancer attribute `access_logs.s3.enabled`, default `false`, per the ELBv2 API model; also set `access_logs.s3.bucket`).

## 503: nothing to send to

The target group has **no registered targets**, or all of them are `unused`. That means not registered, not in a target group used by a listener rule, in an AZ the load balancer doesn't have enabled, or stopped.

```
aws elbv2 describe-target-health --target-group-arn <tg> \
  --query 'TargetHealthDescriptions[].[Target.Id,TargetHealth.State,TargetHealth.Reason,TargetHealth.Description]'
```

The `Reason` code says which case it is (`reference/elb/errors.md`). If every target is **unhealthy**, the load balancer *fails open* and sends to all of them anyway. So a total health-check failure produces 502/504 from broken targets, not 503.

## 502: the target answered badly, or hung up

Ranked by how often each is the cause:

1. **The target's keep-alive timeout is shorter than the load balancer's idle timeout.** The target closes an idle connection the load balancer is about to reuse. The load balancer's idle timeout defaults to 60 s. Set the application server's keep-alive timeout **longer** than that, or lower the load balancer's: `aws elbv2 modify-load-balancer-attributes --load-balancer-arn <lb> --attributes Key=idle_timeout.timeout_seconds,Value=<seconds>` (range 1–4000).
2. **Connection refused or reset (TCP RST), or "host unreachable"** while connecting. Nothing is listening on the target port, or the security group or NACL blocks the load balancer's subnets. In the access log, the processing times are `-1`. The metric is `TargetConnectionErrorCount`.
3. **Malformed response**: invalid headers, or response headers over 32 KB in total.
4. **TLS to the target fails** (HTTPS target group). The target's certificate, key format or ciphers don't match the backend policy the load balancer chose from its front-end policy (`ELBSecurityPolicy-TLS13-1-0-2021-06` for TLS 1.3 listeners, `ELBSecurityPolicy-2016-08` for most others).
5. **A target was deregistered mid-request** and the deregistration delay ran out. Raise the delay for long requests. CloudTrail shows `DeregisterTargets`.
6. **Lambda targets**: a response body over 1 MB (`error_reason` `LambdaResponseTooLarge`), the function timed out (`LambdaUnhandled`), the function threw, or it was throttled. See `guides/lambda/debug-failing-function.md`.

## 504: the target didn't answer in time

1. **Couldn't connect within 10 seconds.** The usual cause is a security group on the target that doesn't allow the load balancer's security group on the traffic port.
2. **Connected, but no response before the idle timeout.** A slow request: fix the application, or raise `idle_timeout.timeout_seconds`.
3. **The NACL on the target subnet blocks the return path**: ephemeral ports 1024–65535 back to the load balancer's subnets.
4. The target sent a `Content-Length` larger than the body it sent.
5. A Lambda target didn't respond before the connection timeout.
6. The TLS handshake to the target took more than 10 seconds.

## Checks in order

1. `describe-target-health`: are targets healthy, and if not, which reason code?
2. From a host in the load balancer's subnets, `curl -v http://<target-private-ip>:<port><health-path>`. Does the target answer, and how quickly?
3. Security groups: the target's group allows the load balancer's group on the traffic **and** health-check ports.
4. NACLs: health-check and traffic ports inbound on the target subnets, and ephemeral ports both ways.
5. Timeouts: the application's keep-alive is longer than the load balancer's idle timeout, and request time is shorter than it.
6. Reachability Analyzer from the load balancer's network interface to the target (`guides/vpc/diagnose-connection-timeout.md`).

## Other load balancer statuses worth recognising

- `460`: the client closed the connection before the load balancer's idle timeout. The client's timeout is shorter.
- `463`: the `X-Forwarded-For` header carries more than 30 IPs.
- `464`: the request's protocol doesn't match the target group's protocol version (HTTP/1.1 vs HTTP/2 or gRPC).
- `000` with HTTP/2: the load balancer closes a connection after 10,000 requests (GOAWAY).

The rest are in `reference/elb/errors.md`.


---
<!-- 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 -->
