400 Bad Request invalid JSON: causes and how to fix it

A 400 Bad Request for invalid JSON means your body did not parse. Check shell quoting, single quotes, trailing commas, and unserialized objects.

5 min readSume
All posts

A 400 Bad Request that says the JSON is invalid means the server could not parse your request body as JSON, so it never got as far as checking your fields. Look at how the body was built: shell quoting that mangled it, single quotes or a trailing comma, an object that was never serialized, or an empty body labeled Content-Type: application/json.

JSON's rules are quoted from RFC 8259 and MDN's JSON.parse errors page, and curl's behavior from its man page and everything curl, all read 2026-09-28. Sume's responses are read from its current API code and its Errors and rate limits docs.

What makes a request body invalid JSON?

Anything a JSON parser rejects. RFC 9110 defines a 400 as a request the server won't process because of a perceived client error, such as malformed request syntax. For JSON, RFC 8259 says a string begins and ends with quotation marks, the " character, and every property name is a string. MDN adds that JSON.parse() does not allow trailing commas or leading zeros such as 01. Four such bodies, as the server receives them:

From RFC 8259, MDN's JSON.parse errors, Using Fetch and Object.prototype.toString() pages, and Sume's Errors and rate limits docs and current API code, read 2026-09-28.
Body the server receivedWhy it failsFix
{'prompt': 'hi'}Single quotes don't delimit JSON strings or property names.Use double quotes, or let a JSON library write the body.
{"prompt": "hi",}A trailing comma after the last member.Remove the comma.
[object Object]An object passed to fetch as the body is converted with toString().Send JSON.stringify(body).
Nothing at allAn empty body labeled application/json.Send a body, or drop the header.

Why does my curl JSON fail on Windows?

Usually because of shell quoting. everything curl's JSON example wraps the body in single quotes, -d '{ "name": "Darth" }', and notes that on Windows single quotes don't work the same way; Sume's docs use the same Unix form. In PowerShell, typing curl can also run an alias for another tool, so type curl.exe, or see posting JSON with Invoke-RestMethod.

The portable fix is to keep the JSON in a file, which needs no extra quoting. -d @file reads the body from a file but strips carriage returns and newlines. --json @file, in curl 7.82.0 and later, posts the file as is and sets Content-Type: application/json and Accept: application/json. curl doesn't check that the data is JSON, so the file still has to be valid. The rest of the command still follows your shell's rules; this one is written for Bash:

# body.json: {"model": "sume/auto", "prompt": "A red fox running through fresh snow"}
curl https://api.sume.com/v1/videos \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Idempotency-Key: fox-video-001" \
  --json @body.json

What does Sume return for a body that isn't JSON?

Sume's docs list both invalid_request and bad_request under 400. In current code, a body that doesn't parse is the bad_request one: it carries the parser's own message and is marked retryable: false with next_action: fix_input, so resending the same bytes won't help.

An empty body sent with the JSON header gets the message Body cannot be empty when content-type is set to 'application/json' instead. A malformed one looks like this, abridged:

{
  "error": {
    "code": "bad_request",
    "message": "Body is not valid JSON but content-type is set to 'application/json'",
    "retryable": false,
    "next_action": "fix_input"
  }
}

What if the JSON parses but I still get a 400?

Then the problem is usually a field. When a field breaks the route's request schema, current code answers 400 invalid_request with details.errors[] entries, each carrying a path, a message, and a type. On a Format run create, an unknown top-level field is 400 unknown_parameter, with a suggestion when the name is close (webook_url → webhook_url).

The key is checked before the body: in current code an invalid key with a broken body gets 401, not 400, so fix a 401 first. A wrong Content-Type is a different error, 415 Unsupported Media Type, and field errors on POST /v1/videos are covered in video generation API 400 errors.

Why do I get an invalid JSON error on a POST with no body?

Because the request still carried Content-Type: application/json. In current code the JSON parser runs whenever that header is present, and an empty body fails it. For a POST that takes no body, such as canceling a Sume job, leave the header off, as the docs' own example does:

curl -X POST https://api.sume.com/v1/jobs/job_123/cancel \
  -H "Authorization: Bearer $SUME_API_KEY"

Sources

Related posts

More in Developers

All Developers posts

Written by Sume