{"record":{"id":"8c54c6691e8b9b72","repo":"odysseus-dev/odysseus","slug":"invalid-json-e","errorCode":null,"errorMessage":"Invalid JSON: {e}","messagePattern":"Invalid JSON: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/chat_routes.py","lineNumber":876,"sourceCode":"            \"model\": actual_model,\n            \"requested_endpoint_id\": requested_route.get(\"endpoint_id\"),\n            \"requested_endpoint_label\": requested_route.get(\"endpoint_label\"),\n            \"endpoint_id\": actual_route.get(\"endpoint_id\"),\n            \"endpoint_label\": actual_route.get(\"endpoint_label\"),\n        }\n\n    # ------------------------------------------------------------------ #\n    # POST /api/chat_stream\n    # ------------------------------------------------------------------ #\n    @router.post(\"/api/chat_stream\")\n    async def chat_stream(request: Request) -> StreamingResponse:\n        body = None\n        try:\n            if request.headers.get(\"content-type\", \"\").startswith(\"application/json\"):\n                try:\n                    body = await request.json()\n                except json.JSONDecodeError as e:\n                    raise HTTPException(400, f\"Invalid JSON: {e}\")\n        except HTTPException:\n            raise\n        except Exception as e:\n            raise HTTPException(400, f\"Request parsing error: {e}\")\n\n        _set_user_time_from_request(request)\n\n        form_data = await request.form()\n        message = form_data.get(\"message\")\n        session = form_data.get(\"session\")\n        attachments = form_data.get(\"attachments\")\n        use_web = form_data.get(\"use_web\")\n        use_research = form_data.get(\"use_research\")\n        time_filter = form_data.get(\"time_filter\")\n        preset_id = form_data.get(\"preset_id\")\n        selected_endpoint_id = str(\n            form_data.get(\"selected_endpoint_id\")\n            or (body or {}).get(\"selected_endpoint_id\")","sourceCodeStart":858,"sourceCodeEnd":894,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/chat_routes.py#L858-L894","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nrequests.post(url, data=str(payload), headers={'Content-Type':'application/json'})\n# after\nimport json\nrequests.post(url, data=json.dumps(payload), headers={'Content-Type':'application/json'})","handlingStrategy":"validation","validationCode":"const raw = JSON.stringify(payload);\ntry { JSON.parse(raw); } catch { fixSerialization(); return; }\nawait fetch(url, {method:'POST', headers:{'Content-Type':'application/json'}, body: raw});","typeGuard":null,"tryCatchPattern":"try { await send(); } catch (e) { if (e.status === 400 && e.message.startsWith('Invalid JSON')) { console.error('payload was not valid JSON', payload); } }","preventionTips":["Always JSON.stringify objects; never interpolate manually","Validate JSON round-trips client-side before sending"],"tags":["json","validation","fastapi","client-error"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}