Summary
This incident stemmed from an AWS Lambda function receiving a POST request without a Content-Type: application/json header, causing API Gateway to treat the body as plain text and resulting in a null request body. The Lambda code attempted to deserialize this null body, triggering a Jackson IllegalArgumentException.
Root Cause
The failure occurred because:
- API Gateway does not parse or pass JSON bodies unless the request declares
Content-Type: application/json. - When the header is missing, API Gateway forwards the event with:
body = nullisBase64Encoded = false
- The Lambda handler calls
objectMapper.readValue(request.getBody(), Order.class)which throws an exception whenrequest.getBody()is null.
Key takeaway: Lambda cannot infer JSON; the client must explicitly declare it.
Why This Happens in Real Systems
This behavior is common because:
- API Gateway relies on the
Content-Typeheader to determine how to interpret the payload. - Without the header, API Gateway assumes raw text, not JSON.
- Java deserialization frameworks (Jackson, Gson) do not accept null input for JSON parsing.
- Many HTTP clients (curl, browser fetch, custom apps) omit Content-Type unless explicitly set.
Real-World Impact
Systems often break in subtle ways:
- Null request bodies cause deserialization failures.
- Silent data loss when upstream services strip or override headers.
- Inconsistent behavior between tools (Postman works, production client fails).
- Hard-to-debug errors because Lambda logs show only a null body, not the original payload.
Example or Code (if necessary and relevant)
A defensive Java handler that avoids null-body crashes:
ObjectMapper mapper = new ObjectMapper();
String body = request.getBody();
if (body == null || body.isEmpty()) {
throw new IllegalArgumentException("Missing JSON body or Content-Type header");
}
Order order = mapper.readValue(body, Order.class);
How Senior Engineers Fix It
Experienced engineers address this at multiple layers:
- Client-side enforcement
- Always set
Content-Type: application/jsonin POST requests.
- Always set
- API Gateway configuration
- Add a mapping template that forces JSON interpretation:
application/json→$input.json('$')
- Add default content handling to convert text to JSON.
- Add a mapping template that forces JSON interpretation:
- Lambda hardening
- Validate
request.getBody()before parsing. - Log missing headers for observability.
- Validate
- Contract enforcement
- Define API schemas (OpenAPI/Swagger) that require JSON content types.
Why Juniors Miss It
This issue is easy to overlook because:
- They assume API Gateway “just knows” the payload is JSON.
- Postman auto-adds headers, masking the problem.
- They trust the Lambda event object without validating it.
- They focus on Lambda code and forget that API Gateway is the real HTTP server.
- They expect Java deserialization to handle nulls gracefully.
Senior engineers know that HTTP headers define the contract — and missing headers break everything.