Introduction A 502 Bad Gateway from API Gateway means the backend integration (usually Lambda) returned an invalid response. Unlike a 500 error, a 502 means the response itself was malformed - wrong format, too large, or improperly encoded.
Symptoms - HTTP 502 response from API Gateway endpoint - API Gateway CloudWatch logs show: "Execution failed due to configuration error: Malformed Lambda proxy response" - CloudWatch metric 5xxError spikes for the API stage - Lambda executes successfully but response is not returned to caller - Response works in Lambda console test but fails through API Gateway
Common Causes - Lambda response missing required fields (statusCode, body, headers) - Response body not a string (must be JSON-stringified) - Response exceeds 6 MB payload limit (REST APIs) or 10 MB (HTTP APIs) - Binary response without proper binary media type configuration - Lambda returning None/null instead of a dict
Step-by-Step Fix 1. **Enable API Gateway execution logging**: ```bash aws apigateway update-stage \ --rest-api-id <api-id> --stage-name prod \ --patch-operations op=replace,path=/*/*/logging/loglevel,value=INFO ```
- 1.Verify Lambda response format (Python example):
- 2.```python
- 3.import json
- 4.def handler(event, context):
- 5.return {
- 6."statusCode": 200,
- 7."headers": {"Content-Type": "application/json"},
- 8."body": json.dumps({"message": "success", "data": []}),
- 9."isBase64Encoded": False
- 10.}
- 11.
` - 12.Common mistakes: returning a string directly, forgetting json.dumps(), or omitting statusCode.
- 13.Handle binary responses correctly:
- 14.```python
- 15.import base64
- 16.def handler(event, context):
- 17.image_data = open('/tmp/image.png', 'rb').read()
- 18.return {
- 19."statusCode": 200,
- 20."headers": {"Content-Type": "image/png"},
- 21."body": base64.b64encode(image_data).decode('utf-8'),
- 22."isBase64Encoded": True
- 23.}
- 24.
` - 25.Ensure every code path returns a dict:
- 26.```python
- 27.# WRONG: Returns None if condition is false
- 28.def handler(event, context):
- 29.if event.get('valid'):
- 30.return {"statusCode": 200, "body": "OK"}
# CORRECT: Always return def handler(event, context): if event.get('valid'): return {"statusCode": 200, "body": "OK"} return {"statusCode": 400, "body": "Invalid request"} ```