Application Load Balancer errors and target health reason codes
Look up an Application Load Balancer problem by HTTP status (the codes the load balancer itself generates, from 400 to 562), by target health reason code (Elb.* and Target.*), or by symptom (no response, certificate name error, ACM pending validation), each with causes and the fix.
markdownreferencev4NPAD-6HHWstage: operatetrust: officialservice: elbinterface: anyALB 400ALB 401ALB 403 WAFALB 408ALB 413ALB 460ALB 463ALB 464ALB 500ALB 501ALB 502ALB 503ALB 504ALB 561ALB 562Target.ResponseCodeMismatchTarget.TimeoutTarget.FailedHealthChecksTarget.NotInUseTarget.NotRegisteredTarget.InvalidStateTarget.IpUnusableElb.InternalErrorNET::ERR_CERT_COMMON_NAME_INVALIDPending ValidationJWTHeaderNotPresent
The load balancer generates the statuses below itself and counts them in HTTPCode_ELB_4XX_Count / HTTPCode_ELB_5XX_Count. Statuses your targets return are passed through and counted in HTTPCode_Target_*. For those, read the application's logs.
Load balancer–generated statuses
Check for every row: find the request in the access log (aws elbv2 describe-load-balancer-attributes --load-balancer-arn <lb> → access_logs.s3.* says whether and where logging is on). elb_status_code with target_status_code - means the load balancer produced the status; error_reason names the cause for authentication, Lambda and WAF failures. Metrics: HTTPCode_ELB_4XX_Count/5XX against HTTPCode_Target_* (guides/elb/fix-alb-5xx.md).
| Status | Causes → fix |
|---|---|
| 400 | Malformed request; request line or single header over 16 KB, or all headers over 64 KB; client closed before sending the full body. Also requests blocked as Severe by desync mitigation |
| 401 | Listener authentication: the IdP denied access or OnUnauthenticatedRequest is deny; claims too large; HTTP/1.0 without a Host header; the scope returns no ID token; login timeout. JWT verification: JWTHeaderNotPresent, JWTRequestFormatInvalid, JWTSignatureValidationFailed, JWTClaimNotPresent, JWTClaimFormatInvalid |
| 403 | An AWS WAF web ACL blocked the request |
| 405 | TRACE method (not supported) |
| 408 | The client sent no data within the idle timeout. TCP keep-alives don't count: send at least 1 byte, or raise the idle timeout |
| 413 | Lambda target and request body over 1 MB; or the header limits above |
| 414 | URL or query string too long |
| 460 | The client closed the connection before the idle timeout elapsed. The client's own timeout is shorter than the request takes |
| 463 | X-Forwarded-For with more than 30 IP addresses |
| 464 | Protocol mismatch with the target group's protocol version: HTTP/1.1 request to a gRPC or HTTP/2 group, gRPC to HTTP/1.1, non-POST HTTP/2 to gRPC |
| 500 | WAF rule execution error; can't reach the IdP token/userinfo or JWKS endpoint (DNS, egress security group or NACL, no internet for an internal load balancer: add NAT); IdP or JWKS slower than 5 s; claims over 11 KB; JWKS over 150 KB or more than 10 keys; target optimizer agent error |
| 501 | Transfer-Encoding other than chunked/identity; WebSocket to a target-optimizer group |
| 502 | TCP RST from the target on connect; ICMP unreachable; the target closed a connection with a request outstanding (keep-alive shorter than the idle timeout); malformed response or headers over 32 KB; deregistration delay elapsed; Lambda response over 1 MB, timeout, error or throttle; TLS handshake error to the target. See guides/elb/fix-alb-5xx.md |
| 503 | No registered targets, or all targets unused; target optimizer has no ready targets |
| 504 | No connection within 10 s; no response within the idle timeout; NACL blocks ephemeral ports 1024–65535 from targets back to the load balancer; Content-Length larger than the body; Lambda didn't respond before the connection timeout; TLS handshake to the target over 10 s |
| 505 | HTTP version mismatch on an established connection |
| 507 | Redirect URL too long |
| 561 | The IdP returned an error during authentication. See the access log's error reason code |
| 562 | The JWKS endpoint returned non-2xx or an invalid key set (format, algorithm, key not convertible, key size not 2K) |
| 000 | HTTP/2 connection closed with GOAWAY after 10,000 requests. The client should reconnect |
Target health reason codes
Run aws elbv2 describe-target-health --target-group-arn <tg>. Elb.* codes come from the load balancer side and Target.* from the target side.
Check for every row: aws elbv2 describe-target-health --target-group-arn <tg> --query 'TargetHealthDescriptions[].[Target.Id,TargetHealth.State,TargetHealth.Reason,TargetHealth.Description]'.
| Reason | State | Meaning → fix |
|---|---|---|
Elb.RegistrationInProgress | initial | Registering. Wait |
Elb.InitialHealthChecking | initial | It must pass one check first. Wait |
Elb.InternalError | unhealthy | Health checks failed due to an internal error on the load balancer side; if it persists, open a support case (UNVERIFIED remedy) |
Target.ResponseCodeMismatch | unhealthy | Health checks failed with these codes: [code]. The path returned something outside the matcher (default 200). Fix the path, or widen Matcher (e.g. 200-399). A 301/302 often means the app redirects HTTP to HTTPS or demands a Host name: the check's Host header is the target's private IP (with :port for non-default ports) |
Target.Timeout | unhealthy | Request timed out. Security group or NACL blocks the health-check port, the target is overloaded, or the path is slow (timeout default 5 s) |
Target.FailedHealthChecks | unhealthy | Not listening on the health-check port, or the app is down |
Target.NotRegistered | unused | Not registered to this target group |
Target.NotInUse | unused | No listener rule uses the target group, or the target's AZ isn't enabled on the load balancer |
Target.InvalidState | unused | The instance is stopped or terminated |
Target.IpUnusable | unused | The IP belongs to a load balancer |
Target.DeregistrationInProgress | draining | Draining connections |
Target.HealthCheckDisabled | unavailable | Health checks are off for the group |
Health checks send GETs with User-Agent: ELB-HealthChecker/2.0. They don't support WebSockets.
Symptoms without a status
| Symptom | Cause → fix | Check |
|---|---|---|
| Internet-facing load balancer never answers | It's attached to private subnets: it needs public subnets routed to an IGW. Or its security group or NACL doesn't admit clients on the listener port. Or VPC Block Public Access is on | aws elbv2 describe-load-balancers --names <lb> --query 'LoadBalancers[0].[Scheme,AvailabilityZones[].SubnetId,SecurityGroups]', then each subnet's route table for 0.0.0.0/0 → igw- |
| Custom domain doesn't reach the load balancer | DNS doesn't resolve to its addresses. Compare dig <domain> with dig <lb DNS name>, and use an alias record (guides/route53/point-domain-at-aws.md) | The two dig calls in the cell |
Browser: NET::ERR_CERT_COMMON_NAME_INVALID | The domain isn't on the listener's certificate, or the client used the load balancer's default DNS name: no public certificate can be issued for *.amazonaws.com | aws elbv2 describe-listener-certificates --listener-arn <l>, then aws acm describe-certificate --certificate-arn <c> --query Certificate.SubjectAlternativeNames |
| Certificate unavailable for the listener | The ACM certificate is still Pending Validation. Complete DNS or email validation | aws acm describe-certificate --certificate-arn <c> --query Certificate.Status |
| Multi-line headers mangled | Not supported: the load balancer inserts : | Send the same request with the header on one line |
High request_processing_time on POSTs | Expected with AWS WAF attached: upload time is counted there (otherwise in target_processing_time) | aws wafv2 get-web-acl-for-resource --resource-arn <lb-arn> |
When none of these fits
Turn on access logs and find the request. The ELB status code with the target's status code says which side answered. A missing target status means the target never replied. Check target health reasons (aws elbv2 describe-target-health) and the target's own logs. If targets are healthy and logs are clean, test the target directly from inside the VPC (guides/vpc/diagnose-connection-timeout.md).