AWS Lambda cannot POST json without application/json header in the Request

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 = null
    • isBase64Encoded = false
  • The Lambda handler calls objectMapper.readValue(request.getBody(), Order.class) which throws an exception when request.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-Type header 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/json in POST requests.
  • API Gateway configuration
    • Add a mapping template that forces JSON interpretation:
      • application/json$input.json('$')
    • Add default content handling to convert text to JSON.
  • Lambda hardening
    • Validate request.getBody() before parsing.
    • Log missing headers for observability.
  • 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.

Leave a Comment