{"record":{"id":"2c4987f0eef2768b","repo":"odysseus-dev/odysseus","slug":"invalid-json-2c4987","errorCode":null,"errorMessage":"Invalid JSON","messagePattern":"Invalid JSON","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/chat_routes.py","lineNumber":2487,"sourceCode":"                restrict_owner=_user is not None,\n                include_legacy_owner=False,\n            )\n        ]\n\n    # ------------------------------------------------------------------ #\n    # POST /api/rewrite — lightweight rewrite of last AI message (no tools)\n    # ------------------------------------------------------------------ #\n    @router.post(\"/api/rewrite\")\n    async def rewrite_message(request: Request) -> StreamingResponse:\n        \"\"\"Rewrite the last AI message with an instruction (shorter/simpler/etc).\n\n        Unlike the full chat pipeline, this does NOT run the agent loop or tools.\n        It just asks the LLM to rewrite the given text.\n        \"\"\"\n        try:\n            body = await request.json()\n        except Exception:\n            raise HTTPException(400, \"Invalid JSON\")\n\n        session_id = body.get(\"session_id\")\n        original_text = body.get(\"original_text\", \"\")\n        instruction = body.get(\"instruction\", \"\")\n\n        if not session_id or not original_text or not instruction:\n            raise HTTPException(400, \"session_id, original_text, and instruction are required\")\n\n        _verify_session_owner(request, session_id)\n\n        try:\n            sess = session_manager.get_session(session_id)\n        except (KeyError, SessionNotFoundError):\n            raise HTTPException(404, \"Session not found\")\n\n        messages = [\n            {\"role\": \"system\", \"content\": (\n                \"You are rewriting a previous response. Follow the instruction exactly. \"","sourceCodeStart":2469,"sourceCodeEnd":2505,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/chat_routes.py#L2469-L2505","documentation":"POST /api/rewrite could not parse the request body as JSON; any exception from request.json() (not just JSONDecodeError) is converted to this 400. The rewrite endpoint expects a JSON body with session_id, original_text, and instruction.","triggerScenarios":"Sending the rewrite request without application/json content type so the body can't be parsed; malformed JSON; empty body; form-encoded data posted to a JSON-only endpoint.","commonSituations":"Client copy-pasted from the chat_stream form-based flow (which uses multipart form data) into this JSON endpoint; fetch without JSON.stringify; proxies stripping or mangling the body.","solutions":["Send Content-Type: application/json with a valid JSON body","Use JSON.stringify({session_id, original_text, instruction}) in the client","Confirm no form-data/multipart wrapper is being applied by the HTTP layer"],"exampleFix":"// before\nfetch('/api/rewrite', {method:'POST', body: `session_id=${id}&instruction=shorter`})\n// after\nfetch('/api/rewrite', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({session_id: id, original_text: text, instruction: 'shorter'})})","handlingStrategy":"validation","validationCode":"const body = JSON.stringify({session_id, original_text, instruction});\nJSON.parse(body); // sanity round-trip\nawait fetch('/api/rewrite', {method:'POST', headers:{'Content-Type':'application/json'}, body});","typeGuard":null,"tryCatchPattern":"try { await rewrite(...); } catch (e) { if (e.status === 400 && e.message === 'Invalid JSON') { console.error('body serialization bug', lastPayload); } }","preventionTips":["Always set Content-Type: application/json and JSON.stringify the body","Don't reuse form-encoded helpers from chat_stream for this JSON endpoint"],"tags":["json","validation","rewrite","client-error"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}