Open Source API Gateway

400 Bad Request: JSON Protection Violation

Membrane API Gateway returns 400 Bad Request with the title JSON Protection Violation when the jsonProtection plugin rejects the request body. The body exceeds a configured limit, is not well-formed JSON, is not JSON at all, or is a multipart body that cannot be processed.

The Error Response

The response contains the status 400 Bad Request, the title JSON Protection Violation, a detail that names the violation, for example Exceeded maxDepth., the fields line and column with the position in the body, the problem type https://membrane-api.io/problems/user and a link to this page. The type user means that the request caused the problem, not an internal failure of the gateway.

This detailed response is only sent when reportError is on. By default, it is on in development mode and off in production mode. With reportError off, the client receives a plain 400 Bad Request without details.

What the jsonProtection Plugin Does

The jsonProtection plugin protects backends from oversized and deeply nested JSON documents that are used in denial of service attacks. It reads the body as a stream and stops as soon as a limit is exceeded, so the offending body never reaches the backend. See JSON Protection for an introduction.

Common Causes

A Limit Is Exceeded

The detail says which limit was exceeded:

LimitRestricts
maxTokensThe total number of tokens in the document
maxSizeThe size of the body in bytes
maxDepthThe nesting depth of objects and arrays
maxStringLengthThe length of string values
maxKeyLengthThe length of field names
maxObjectSizeThe number of fields in an object
maxArraySizeThe number of elements in an array

The Body Is Not Well-Formed JSON

The body has a syntax error, contains the same key twice in one object, or contains __proto__ as a key while blockProto is on, which is the default. __proto__ keys are used in prototype pollution attacks against JavaScript backends.

The Content Type Is Not JSON

The Content-Type of the request, or of a part of a multipart request, is not a JSON type. With otherContentTypes set to reject, the default, such bodies are rejected.

The Multipart Body Cannot Be Processed

A part is larger than maxSize, a part is itself a multipart, a part uses an unsupported Content-Transfer-Encoding, or the multipart structure is malformed.

How to Fix It

  1. Read the detail and the line and column fields to find the offending part of the body.
  2. As a client, send well-formed JSON without duplicate keys, within the published limits and with a JSON Content-Type such as application/json.
  3. As an operator, raise the matching limit if legitimate requests are rejected.
api:
port: 2000
flow:
- jsonProtection:
maxDepth: 100
maxArraySize: 5000
target:
url: https://api.predic8.de
api:
  port: 2000
  flow:
    - jsonProtection:
        maxDepth: 100
        maxArraySize: 5000
  target:
    url: https://api.predic8.de

To let non-JSON bodies or parts pass unchecked, for example file uploads next to a JSON part, set otherContentTypes: skip on the plugin.

Details in Production Mode

Unlike most errors, this response is not shortened in production mode. Whenever it is sent, it contains the detail, the position in the body and the link to this page, even with production: true. In production mode, reportError is off by default, so clients usually receive a plain 400 Bad Request instead. If you set reportError: true explicitly, the details are sent in production, too. They reveal your configured limits, so turn them off unless your clients need them:

api:
port: 2000
flow:
- jsonProtection:
reportError: false
target:
url: https://api.predic8.de
api:
  port: 2000
  flow:
    - jsonProtection:
        reportError: false
  target:
    url: https://api.predic8.de

Related Documentation

Configuration reference:

Tutorials with runnable examples:

← All Membrane error messages

Still stuck? See the troubleshooting guide or ask on GitHub Issues. For commercial support, contact info@predic8.de.