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

  1. Validate the request body with JSON.parse before sending, or rely on your client's JSON serializer (fetch with JSON.stringify, axios default).
  2. Set Content-Type: application/json and ensure the client actually serializes the object instead of passing a raw string incorrectly.
  3. If using curl, wrap the -d payload in single quotes and check for shell quoting issues; print the exact bytes being sent.
  4. 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

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

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/9589c8692fd4f675. Report an issue: GitHub.