DEV Community

Cover image for Lambda + ALB 503 Error Debugging Guide
Anthony Uketui
Anthony Uketui

Posted on

Lambda + ALB 503 Error Debugging Guide

Debugging AWS Lambda + ALB 503 Errors: A Step‑by‑Step Guide to Event Format Mismatches

When I first put an AWS Lambda behind an Application Load Balancer (ALB), everything looked correct:

  • The Lambda worked perfectly when tested directly.
  • The ALB target group was configured for Lambda.
  • Listener rules and routing looked fine.
  • Permissions were in place.

But calling the Lambda through the ALB kept returning:

503 Service Unavailable

Meanwhile, the same Lambda worked through a Function URL and API Gateway v2. The root cause turned out to be a subtle event format mismatch between what the Lambda handler expected and what ALB actually sends.

This post walks through the exact debugging steps, how I identified the mismatch, and how to fix it.


Step 1: Verify Lambda Function Health

Estimated Time: 2–3 minutes

Action: Test the Lambda function directly.

  • Use a Function URL or the Lambda console test feature.
  • Confirm that the function executes successfully.

Expected Outcome: Lambda works fine in isolation.

Key Insight:

If the Lambda works when tested directly, the issue is in the integration layer (ALB), not the Lambda code itself.


Step 2: Check ALB Target Group Configuration

Estimated Time: 5 minutes

Action: Verify your ALB target group.

  • Target type: lambda
  • Lambda function registered as target
  • Health checks: disabled (normal for Lambda)
  • Target status: unavailable (expected for Lambda targets)

Key Insight:

“Unavailable” status with disabled health checks is normal for Lambda targets — it is not the cause of 503 errors.


Step 3: Verify ALB Permissions

Estimated Time: 3 minutes

Action: Check the Lambda resource policy to ensure ALB can invoke the function:

aws lambda get-policy --function-name my-lambda-function
Enter fullscreen mode Exit fullscreen mode

Verify:

  • The ALB has lambda:InvokeFunction permission.
  • The ALB ARN is present in the policy.

Key Insight:

Missing permissions would usually result in 403 or 502 errors, not 503. Still, it’s worth ruling out early.


Step 4: Analyze ALB Listener Rules

Estimated Time: 10 minutes

Action: Check routing configuration on the ALB listener.

For example:

  • Rule priority: 155
  • Path pattern: /plugin/*
  • Host header: api.example.com
  • Target group: MY-LAMBDA-TG

Key Insight:

ALB routing is strict — both path and host header must match exactly. A mismatch here can easily cause requests to hit the wrong target or no target at all.


Step 5: Test with Correct Routing

Estimated Time: 5 minutes

Action: Hit the ALB with the correct host and path.

curl -H "Host: api.example.com" https://my-alb-123456.eu-west-2.elb.amazonaws.com/plugin/test
Enter fullscreen mode Exit fullscreen mode

Result: In my case, this still returned 503, even though routing looked correct.

Key Insight:

Correct routing alone does not guarantee success. If the Lambda works directly but fails through the ALB, start suspecting an event format mismatch.


Step 6: Compare Working vs Non‑Working Scenarios

Estimated Time: 5 minutes

Pattern Recognition:

  • Function URL: works
  • API Gateway v2: works
  • ALB: fails (503)

Key Insight:

The working integrations (Function URL and API Gateway v2) share the same event format, which ALB does not use. That difference becomes important.


Step 7: Examine the Lambda Handler Signature

Estimated Time: 3 minutes

Action: Inspect the Lambda handler to see what type of event it expects.

For example (pseudo-steps):

aws lambda get-function --function-name my-lambda-function
# Then inspect / decompile the handler class if needed
javap -cp . -public com.example.demo.LambdaRequestHandler
Enter fullscreen mode Exit fullscreen mode

Handler Signature Example (Java):

public class LambdaRequestHandler implements RequestHandler<APIGatewayV2HTTPEvent, LambdaResponse> {
    @Override
    public LambdaResponse handleRequest(APIGatewayV2HTTPEvent event, Context context) {
        // ...
    }
}
Enter fullscreen mode Exit fullscreen mode

Key Insight:

The handler here expects APIGatewayV2HTTPEvent, which is the event format used by API Gateway HTTP APIs and Function URLsnot the ApplicationLoadBalancerRequestEvent style payload that ALB sends.


Step 8: Analyze CloudWatch Logs

Estimated Time: 2 minutes

Action: Look for exceptions in CloudWatch Logs.

aws logs filter-log-events \
  --log-group-name "/aws/lambda/my-lambda-function" \
  --filter-pattern "Exception" \
  --max-items 5
Enter fullscreen mode Exit fullscreen mode

Example Error:

NullPointerException: Cannot invoke "String.hashCode()" because "<localX>" is null
    at com.example.demo.LambdaRequestHandler.handleRequest(LambdaRequestHandler.java:77)
Enter fullscreen mode Exit fullscreen mode

Root Cause:

Because the handler expects a specific JSON structure (APIGatewayV2HTTPEvent), it tries to access fields that don’t exist in the ALB event → resulting in NullPointerException and ultimately a 503 from ALB.


Step 9: Identify the Event Format Mismatch

Estimated Time: 2 minutes

Let’s compare the incoming event shapes.

Expected by Lambda (API Gateway v2 / Function URL):

{
  "version": "2.0",
  "routeKey": "POST /plugin",
  "rawPath": "/plugin/payment",
  "httpMethod": "POST",
  "headers": { "...": "..." },
  "body": "..."
}
Enter fullscreen mode Exit fullscreen mode

Sent by ALB:

{
  "requestContext": { "elb": { /* ... */ } },
  "httpMethod": "POST",
  "path": "/plugin/payment",
  "headers": { "...": "..." },
  "body": "..."
}
Enter fullscreen mode Exit fullscreen mode

Problem:

The JSON structure is different. Fields your code assumes exist (e.g., version, routeKey, rawPath) are not present in the ALB event. Accessing them directly leads to NullPointerException and a 503 at the ALB level.


Step 10: Verify with Test Events

Estimated Time: 3 minutes

You can simulate both event types in the Lambda console.

ALB Test Event (will fail if your handler expects API Gateway v2):

{
  "requestContext": {
    "elb": {
      "targetGroupArn": "arn:aws:elasticloadbalancing:region:account-id:targetgroup/my-target-group/1234567890abcdef"
    }
  },
  "httpMethod": "POST",
  "path": "/plugin/payment",
  "headers": {
    "content-type": "application/json"
  },
  "body": "{\"test\": \"data\"}"
}
Enter fullscreen mode Exit fullscreen mode

API Gateway v2 Test Event (will work with APIGatewayV2HTTPEvent handler):

{
  "version": "2.0",
  "routeKey": "POST /plugin",
  "rawPath": "/plugin/payment",
  "httpMethod": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "body": "{\"test\": \"data\"}"
}
Enter fullscreen mode Exit fullscreen mode

Result:

If the API Gateway v2 event works but the ALB event fails with an exception, you’ve confirmed the event format mismatch as the root cause.


The Fix: Update the Lambda Handler to Support ALB

Once you know the issue is an event format mismatch, you have two main options:

Option 1: Change the Handler Input Type to ALB’s Event

For Java, for example:

Before (expects API Gateway v2):

import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent;

public class LambdaRequestHandler implements RequestHandler<APIGatewayV2HTTPEvent, LambdaResponse> {
    @Override
    public LambdaResponse handleRequest(APIGatewayV2HTTPEvent event, Context context) {
        // Your existing logic
    }
}
Enter fullscreen mode Exit fullscreen mode

After (expects ALB event):

import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;

public class LambdaRequestHandler implements RequestHandler<ApplicationLoadBalancerRequestEvent, LambdaResponse> {
    @Override
    public LambdaResponse handleRequest(ApplicationLoadBalancerRequestEvent event, Context context) {
        // Adapt your logic to read from ALB's event shape:
        // event.getPath(), event.getHttpMethod(), event.getHeaders(), event.getBody(), etc.
    }
}
Enter fullscreen mode Exit fullscreen mode

This makes the function compatible with ALB’s event structure.


Option 2: Use an Adapter Layer

If you need to support multiple event sources (e.g., API Gateway v2 and ALB) with the same business logic:

  1. Accept the raw event (or use a common internal model).
  2. Detect which event type you received (ALB vs API Gateway v2).
  3. Map it into a unified internal request object.
  4. Pass that object to your core handler logic.

Conceptually:

public class LambdaEntryPoint implements RequestHandler<Map<String, Object>, LambdaResponse> {
    @Override
    public LambdaResponse handleRequest(Map<String, Object> rawEvent, Context context) {
        InternalRequest request = EventAdapter.toInternalRequest(rawEvent);
        return CoreHandler.handle(request);
    }
}
Enter fullscreen mode Exit fullscreen mode

This pattern decouples your core business logic from AWS-specific event shapes.


Quick Diagnosis Checklist for Lambda + ALB 503 Errors

Step Action
Function Health Test Lambda directly
Permissions Confirm ALB invoke policy
Routing Rules Path & host header check
Event Format Compare working vs failing integration
Logs Check for NPE or other stack traces

Common Gotchas:

  • Ignoring ALB event format.
  • Assuming Lambda target health status matters for 503s.
  • Missing Host header or path mismatch.
  • Testing with the wrong event data in the console.
  • Handler tightly coupled to one event type (e.g., API Gateway v2 only).

Key Takeaways

  1. Lambda + ALB 503 errors can also happen due to event format mismatch, not just networking or permissions.
  2. The handler signature dictates the expected input. If it expects APIGatewayV2HTTPEvent, it won’t magically understand ALB’s event format.
  3. Function URLs and API Gateway v2 share the same event format, so a handler that works there may still fail behind an ALB.
  4. ALB sends a different JSON structure (e.g., requestContext.elb, different path fields), which can break your code if you assume API Gateway-style fields.
  5. CloudWatch logs reveal stack traces and NPEs — always check them first when debugging 503s.

Top comments (0)