decolua/9router · error
Invalid JSON body
Error message
Invalid JSON body
What it means
The chat endpoint (/v1/chat/completions) could not parse the request body as JSON. handleChat calls request.json() inside a try/catch; any parse failure (SyntaxError) is converted into a 400 response with this message. The gateway requires a well-formed JSON body in one of the supported formats (OpenAI, Claude, Gemini, Responses).
Source
Thrown at src/sse/handlers/chat.js:37
import { augmentModelsWithCapacityAdapter, withCapacityAdapterStripping, getActiveAdapterStrategy } from "open-sse/services/capacityAdapter.js";
import { handleBypassRequest } from "open-sse/utils/bypassHandler.js";
import { HTTP_STATUS } from "open-sse/config/runtimeConfig.js";
import { detectFormatByEndpoint } from "open-sse/translator/formats.js";
import * as log from "../utils/logger.js";
import { updateProviderCredentials, checkAndRefreshToken } from "../services/tokenRefresh.js";
import { getProjectIdForConnection } from "open-sse/services/projectId.js";
/**
* Handle chat completion request
* Supports: OpenAI, Claude, Gemini, OpenAI Responses API formats
* Format detection and translation handled by translator
*/
export async function handleChat(request, clientRawRequest = null) {
let body;
try {
body = await request.json();
} catch {
log.warn("CHAT", "Invalid JSON body");
return errorResponse(HTTP_STATUS.BAD_REQUEST, "Invalid JSON body");
}
// Build clientRawRequest for logging (if not provided)
if (!clientRawRequest) {
const url = new URL(request.url);
clientRawRequest = {
endpoint: url.pathname,
body,
headers: Object.fromEntries(request.headers.entries())
};
}
const modelStr = body.model;
// Request summary is emitted as the unified "▶" line in chatCore (has fmt/thinking/account)
// Log API key (masked)
const authHeader = request.headers.get("Authorization");View on GitHub (pinned to 90b52e06ff)
Solutions
- Validate the request body with JSON.parse before sending, or rely on your client's JSON serializer (fetch with JSON.stringify, axios default).
- Set Content-Type: application/json and ensure the client actually serializes the object instead of passing a raw string incorrectly.
- If using curl, wrap the -d payload in single quotes and check for shell quoting issues; print the exact bytes being sent.
- Check for proxies/middleware that may truncate or re-encode the body between client and the 9Router gateway.
Example fix
// before
await fetch(url, { method: 'POST', body: payload }); // payload is an object, sent as '[object Object]'
// after
await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
}); Defensive patterns
Strategy: validation
Validate before calling
const payload = JSON.stringify(body);
JSON.parse(payload); // throws before the request if body is not serializable/valid JSON
if (!body || typeof body !== 'object') throw new TypeError('chat body must be an object'); Type guard
function isValidJsonBody(text) {
try { const v = JSON.parse(text); return v !== null && typeof v === 'object'; }
catch { return false; }
} Try / catch
const res = await fetch(url, opts);
if (res.status === 400) {
const err = await res.json();
if (err?.error?.message === 'Invalid JSON body') {
console.error('Payload was not valid JSON:', opts.body);
}
} Prevention
- Always serialize with JSON.stringify and set Content-Type: application/json.
- Round-trip JSON.parse(JSON.stringify(payload)) in tests for hand-built payloads.
- Beware shell quoting when using curl with inline JSON.
- Check proxies/middleware for body truncation or re-encoding.
When it happens
Trigger: POST to /v1/chat/completions where the raw body is not valid JSON: empty body, trailing garbage, truncated body, or a body with invalid JSON syntax such as unquoted keys, single quotes, or an unclosed brace.
Common situations: Sending the body without a JSON Content-Type while the client serializes incorrectly; curl commands where quotes get mangled by the shell; proxy/intermediary truncating large request bodies; a script posting FormData or plain text instead of JSON; SDK misconfiguration pointing at the gateway with a text payload.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/9589c8692fd4f675.
Report an issue: GitHub.