serper.dev 400 invalid JSON body
Fixes Serper.dev HTTP 400 invalid JSON body errors on the search endpoint. Use when a POST to google.serper.dev/search fails with 400 and the body mentions invalid JSON. Not for 401 key errors, 429 rate limits, or empty-result issues.
TL;DR
The body you sent is not valid JSON. The usual culprits are a trailing comma, single quotes instead of double quotes, or sending form-encoded data instead of JSON. Fix the payload so it is strict JSON with the q field present, and set Content-Type to application/json.
serper.dev 400 invalid JSON bodyUse this when
- POST https://google.serper.dev/search returns 400 with an invalid-JSON message
- The same query works in curl but fails from your code (or vice versa)
- You are building the body with string concatenation
Not for this skill when
- Serper returns 401/403 (the X-API-KEY header is missing or wrong)
- Serper returns 429 (rate limit; back off instead)
- Results return but are wrong or empty (query wording, not payload shape)
Steps
- Print the exact raw body bytes you are sending, before headers. Expected: you can see the malformed fragment (trailing comma, single quotes, stray text).
- Validate it with json.loads in Python or JSON.parse in Node. Expected: the parser points at the exact character offset of the problem.
- Rebuild the body with a real serializer (json.dumps / JSON.stringify), never string templates. Expected: valid strict JSON every time.
- Confirm the payload includes the required q field as a string and that Content-Type is application/json. Expected: 200 with a results array.
- Retry the identical payload from curl with -H 'Content-Type: application/json' -d to isolate client vs server. Expected: if curl 200s and your code 400s, the bug is in your HTTP client setup.
Variant phrasings
serper invalid json body error
Run the body through a strict JSON parser to find the offending character.
serper.dev 400 bad request search
Check Content-Type first: many 400s are form-encoded bodies sent to a JSON endpoint.
Tool/version compatibility
Serper search API v1 (google.serper.dev). Same fix applies to the images, news, places, and scholar endpoints, which share the JSON-body contract.
Why it happens
The endpoint parses the body as strict JSON (RFC 8259): no trailing commas, no comments, double quotes only. Common producers violate this: Python f-string templates, requests.post(data=...) instead of json=..., or curl -d without the JSON content type. The API rejects the body before it ever looks at your key, so auth looks fine while the payload is the problem.
Edge cases / pitfalls
- Non-ASCII queries must be UTF-8 encoded; some clients double-encode and produce mojibake, which can also 400.
- An empty body or a body that is just whitespace 400s the same way.
- Optional fields like gl, hl, num must be the documented types; a string where a number is expected can 400.
- Read keys via os.environ.get("SERPERAPIKEY") and never log or print the value.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_ktZQF8nOriqScKqCCLdKgg