odysseus-dev/odysseus · error · HTTPException
Invalid JSON: {e}
Error message
Invalid JSON: {e} What it means
The streaming chat endpoint received a request with Content-Type application/json whose body failed to parse as JSON. json.JSONDecodeError is caught and re-raised as a 400 with the parser's message, so the exact syntax problem (position, error class) is included.
Source
Thrown at routes/chat_routes.py:876
"model": actual_model,
"requested_endpoint_id": requested_route.get("endpoint_id"),
"requested_endpoint_label": requested_route.get("endpoint_label"),
"endpoint_id": actual_route.get("endpoint_id"),
"endpoint_label": actual_route.get("endpoint_label"),
}
# ------------------------------------------------------------------ #
# POST /api/chat_stream
# ------------------------------------------------------------------ #
@router.post("/api/chat_stream")
async def chat_stream(request: Request) -> StreamingResponse:
body = None
try:
if request.headers.get("content-type", "").startswith("application/json"):
try:
body = await request.json()
except json.JSONDecodeError as e:
raise HTTPException(400, f"Invalid JSON: {e}")
except HTTPException:
raise
except Exception as e:
raise HTTPException(400, f"Request parsing error: {e}")
_set_user_time_from_request(request)
form_data = await request.form()
message = form_data.get("message")
session = form_data.get("session")
attachments = form_data.get("attachments")
use_web = form_data.get("use_web")
use_research = form_data.get("use_research")
time_filter = form_data.get("time_filter")
preset_id = form_data.get("preset_id")
selected_endpoint_id = str(
form_data.get("selected_endpoint_id")
or (body or {}).get("selected_endpoint_id")View on GitHub (pinned to f9235ebbf1)
Solutions
- Validate the payload with JSON.parse (JS) or json.loads (Python) before sending
- Send with JSON.stringify(obj) / json= in requests, never a raw template string
- Check for proxy truncation if the error position equals the end of a shortened body
Example fix
# before
requests.post(url, data=str(payload), headers={'Content-Type':'application/json'})
# after
import json
requests.post(url, data=json.dumps(payload), headers={'Content-Type':'application/json'}) Defensive patterns
Strategy: validation
Validate before calling
const raw = JSON.stringify(payload);
try { JSON.parse(raw); } catch { fixSerialization(); return; }
await fetch(url, {method:'POST', headers:{'Content-Type':'application/json'}, body: raw}); Try / catch
try { await send(); } catch (e) { if (e.status === 400 && e.message.startsWith('Invalid JSON')) { console.error('payload was not valid JSON', payload); } } Prevention
- Always JSON.stringify objects; never interpolate manually
- Validate JSON round-trips client-side before sending
When it happens
Trigger: POST /api/chat_stream with Content-Type: application/json and a malformed body: trailing commas, single quotes, unescaped newlines, truncated payload from a proxy or client bug.
Common situations: Hand-crafted curl requests with quoting mistakes; a proxy or LB truncating large bodies; client serializing form data as a string instead of JSON.stringify; encoding issues introducing BOM or control characters.
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
- text is required
- Request parsing error: {e}
- Invalid JSON
- session_id, original_text, and instruction are required
- Invalid remote_host — must be host or user@host, no SSH opti
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/8c54c6691e8b9b72.
Report an issue: GitHub.