# Fix AWS API Gateway 500 Error
Your API Gateway is returning 500 Internal Server Error responses, and the generic message "Internal Server Error" tells you nothing about what's actually wrong. The problem could be in your Lambda function, your backend integration, request/response mapping, or even API Gateway configuration itself.
Let's systematically track down the root cause.
Diagnosis Commands
First, get basic information about your API:
aws apigateway get-rest-apis \
--query 'items[*].[id,name,version]' \
--output tableGet details about a specific API:
aws apigateway get-rest-api \
--rest-api-id abc123def4 \
--query '[id,name,version,createdDate]'List the resources and methods:
aws apigateway get-resources \
--rest-api-id abc123def4 \
--query 'items[*].[id,path,resourceMethods]'Check the method configuration:
aws apigateway get-method \
--rest-api-id abc123def4 \
--resource-id xyz123 \
--http-method GET \
--query '[httpMethod,authorizationType,integration.type,integration.uri]'Enable access logging if not already enabled:
aws apigateway update-stage \
--rest-api-id abc123def4 \
--stage-name prod \
--patch-operations op=replace,path=/accessLogSettings/destinationArn,value=arn:aws:logs:us-east-1:123456789012:log-group:api-gateway-logs,op=replace,path=/accessLogSettings/format,value='{"requestId":"$context.requestId","ip":"$context.identity.sourceIp","caller":"$context.identity.caller","user":"$context.identity.user","requestTime":"$context.requestTime","httpMethod":"$context.httpMethod","resourcePath":"$context.resourcePath","status":"$context.status","protocol":"$context.protocol","responseLength":"$context.responseLength","integrationError":"$context.integrationErrorMessage"}'Create the log group first if needed:
aws logs create-log-group \
--log-group-name /aws/apigateway/abc123def4/prodView recent access logs:
aws logs filter-log-events \
--log-group-name /aws/apigateway/abc123def4/prod \
--start-time $(date -u -d '1 hour ago' +%s)000 \
--filter-pattern "500" \
--query 'events[*].message' \
--output textCheck CloudWatch metrics for error patterns:
aws cloudwatch get-metric-statistics \
--namespace AWS/ApiGateway \
--metric-name 5XXError \
--dimensions Name=ApiName,Value=my-api Name=Stage,Value=prod \
--start-time $(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 3600 \
--statistics Sum \
--output tableCommon Causes and Solutions
Lambda Integration Errors
For Lambda integrations, check the Lambda logs:
aws logs filter-log-events \
--log-group-name /aws/lambda/my-function \
--start-time $(date -u -d '1 hour ago' +%s)000 \
--query 'events[*].message' \
--output textCheck for Lambda errors:
aws cloudwatch get-metric-statistics \
--namespace AWS/Lambda \
--metric-name Errors \
--dimensions Name=FunctionName,Value=my-function \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 300 \
--statistics SumCommon Lambda issues:
Incorrect response format:
Lambda must return a specific response format for API Gateway:
// Correct format
exports.handler = async (event) => {
return {
statusCode: 200,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ message: "Success" })
};
};Timeout:
aws lambda get-function-configuration \
--function-name my-function \
--query 'Timeout'Increase timeout if needed:
aws lambda update-function-configuration \
--function-name my-function \
--timeout 30Memory issues:
aws cloudwatch get-metric-statistics \
--namespace AWS/Lambda \
--metric-name MemoryUtilization \
--dimensions Name=FunctionName,Value=my-function \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 300 \
--statistics MaximumBackend Integration Issues
For HTTP integrations, test the backend directly:
```bash # Test with curl curl -v https://backend-api.example.com/endpoint
# Check backend health curl -X GET https://backend-api.example.com/health ```
Check integration configuration:
aws apigateway get-integration \
--rest-api-id abc123def4 \
--resource-id xyz123 \
--http-method GET \
--query '[type,uri,httpMethod,requestTemplates,responseTemplates]'Connection timeout:
If your backend is slow, increase the integration timeout:
aws apigateway update-integration \
--rest-api-id abc123def4 \
--resource-id xyz123 \
--http-method GET \
--patch-operations op=replace,path=/timeoutInMillis,value=29000Maximum timeout is 29 seconds for API Gateway.
Backend unavailable:
Check if your backend endpoints are reachable:
```bash # For ALB/NLB backends aws elbv2 describe-target-health \ --target-group-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/my-targets/abc123
# For EC2 backends aws ec2 describe-instance-status \ --instance-ids i-1234567890abcdef0 ```
Request/Response Mapping Issues
VTL (Velocity Template Language) mapping errors can cause 500s.
Check request templates:
aws apigateway get-integration \
--rest-api-id abc123def4 \
--resource-id xyz123 \
--http-method POST \
--query 'requestTemplates'Test mapping templates:
aws apigateway test-invoke-method \
--rest-api-id abc123def4 \
--resource-id xyz123 \
--http-method POST \
--body '{"test": "data"}' \
--query '[status,body,log]'Common VTL errors:
Syntax error in template:
```velocity ## Bad - missing closing brace #set($input = $input.json('$')
Good #set($input = $input.json('$')) ```
Missing required fields:
## Ensure all required fields are present
{
"statusCode": 200,
"body": $input.json('$')
}Update the integration with correct templates:
aws apigateway put-integration \
--rest-api-id abc123def4 \
--resource-id xyz123 \
--http-method POST \
--type AWS_PROXY \
--integration-http-method POST \
--uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123456789012:function:my-function/invocations \
--request-templates '{"application/json": "#set($inputRoot = $input.path('$'))\n{\n \"body\": $input.json('$')\n}"}'Authorizer Errors
Custom authorizers can cause 500s if they fail:
aws apigateway get-authorizers \
--rest-api-id abc123def4 \
--query 'items[*].[id,name,type,authorizerUri]'Test authorizer directly:
aws lambda invoke \
--function-name my-authorizer \
--payload '{"type":"TOKEN","authorizationToken":"Bearer test-token"}' \
--cli-binary-format raw-in-base64-out \
authorizer-response.json && cat authorizer-response.jsonCheck authorizer logs:
aws logs filter-log-events \
--log-group-name /aws/lambda/my-authorizer \
--start-time $(date -u -d '1 hour ago' +%s)000 \
--query 'events[*].message'Throttling
API Gateway has default limits that can cause 500s:
aws apigateway get-account \
--query 'throttleSettings'Check usage plans and throttling:
aws apigateway get-usage-plans \
--query 'items[*].[id,name,throttle]'Increase limits if needed (request AWS support for account-level increases):
aws apigateway update-stage \
--rest-api-id abc123def4 \
--stage-name prod \
--patch-operations op=replace,path=/throttling/burstLimit,value=1000,op=replace,path=/throttling/rateLimit,value=500Stage Variables and Environment Issues
If your integration uses stage variables:
aws apigateway get-stage \
--rest-api-id abc123def4 \
--stage-name prod \
--query 'variables'Update stage variables:
aws apigateway update-stage \
--rest-api-id abc123def4 \
--stage-name prod \
--patch-operations op=replace,path=/variables/apiEndpoint,value=https://api.example.comCORS Issues (Manifesting as 500)
Sometimes CORS errors get reported as 500:
aws apigateway get-method-response \
--rest-api-id abc123def4 \
--resource-id xyz123 \
--http-method OPTIONS \
--status-code 200Add CORS headers:
aws apigateway update-method-response \
--rest-api-id abc123def4 \
--resource-id xyz123 \
--http-method OPTIONS \
--status-code 200 \
--patch-operations \
op=replace,path=/responseParameters/method.response.header.Access-Control-Allow-Origin,value="'*'" \
op=replace,path=/responseParameters/method.response.header.Access-Control-Allow-Methods,value="'GET,POST,OPTIONS'" \
op=replace,path=/responseParameters/method.response.header.Access-Control-Allow-Headers,value="'Content-Type,Authorization'"Verification Steps
After making changes, test your API:
```bash # Test with API Gateway test-invoke-method aws apigateway test-invoke-method \ --rest-api-id abc123def4 \ --resource-id xyz123 \ --http-method GET \ --query '[status,body]'
# Make actual API call curl -v https://abc123def4.execute-api.us-east-1.amazonaws.com/prod/my-endpoint
# Monitor error rate aws cloudwatch get-metric-statistics \ --namespace AWS/ApiGateway \ --metric-name 5XXError \ --dimensions Name=ApiName,Value=my-api Name=Stage,Value=prod \ --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --period 300 \ --statistics Sum ```
Set up an alarm for 5XX errors:
aws cloudwatch put-metric-alarm \
--alarm-name api-gateway-5xx-errors \
--alarm-description "API Gateway 5XX errors" \
--namespace AWS/ApiGateway \
--metric-name 5XXError \
--dimensions Name=ApiName,Value=my-api Name=Stage,Value=prod \
--statistic Sum \
--period 60 \
--threshold 5 \
--comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:123456789012:alertsCreate a diagnostic script:
```bash #!/bin/bash API_ID="abc123def4" STAGE="prod" REGION="us-east-1"
echo "Checking API Gateway health..."
echo "1. Checking recent 5XX errors..." aws cloudwatch get-metric-statistics \ --namespace AWS/ApiGateway \ --metric-name 5XXError \ --dimensions Name=ApiName,Value=my-api Name=Stage,Value=$STAGE \ --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --period 300 \ --statistics Sum
echo "2. Testing endpoint..." curl -s -o /dev/null -w "HTTP Status: %{http_code}\n" \ https://$API_ID.execute-api.$REGION.amazonaws.com/$STAGE/health
echo "3. Checking Lambda errors (if applicable)..." aws cloudwatch get-metric-statistics \ --namespace AWS/Lambda \ --metric-name Errors \ --dimensions Name=FunctionName,Value=my-function \ --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --period 300 \ --statistics Sum
echo "Diagnostic complete." ```