Skip to main content
invalid_body means OpenType could not accept the body of a POST /v1/runs request, or the query string of a GET /v1/runs request. Read this page when a run is refused with a 400 and you need to know which field to change.

What happened

The request does not fit the runs contract. It was refused before a run existed, so nothing was stored and nothing was charged. Routes:
  • POST /v1/runs: the JSON body.
  • GET /v1/runs: the limit and offset query parameters.
Every message starts with the request body is not valid: and ends with one of the reasons below. Branch on code, and log message for the person who fixes the request.

Reading the request

Prompt and contract

A field sent on the wrong kind

On POST /v1/runs the credential is checked first, so a request with a bad key and a bad body gets a 401. The reasons under “Reading the request” are checked next, before the runs_write scope and the Idempotency-Key header. The prompt, contract and wrong-kind reasons are checked after them.

How to fix

  1. Take the reason after the prefix and find it in the tables above.
  2. If a decision run fails with ... is only valid on a decision run, add "kind": "decision".
  3. Send Content-Type: application/json. Python requests sets it for you when you pass json=.
  4. Remove any field the contract does not list, and check the spelling of the ones it does.
  5. Send the corrected request. The first attempt was refused before a run existed, so you may keep the same Idempotency-Key.
Which fields each kind accepts: Decision runs also accept an optional model, either neon-1.1 or neon-latest. Any other value is refused with unknown_model, not with invalid_body.

Example

A decision run that passes these checks:
  • Problem codes - every code, its status, and whether a retry can help.
  • Errors - the error envelope and why you branch on code, not message.
  • Decision runs - the full decision body, field by field.
  • Verdict runs - the verdict body and its schema.
  • Error handling - a retry policy that never resends a 400 unchanged.