odysseus-dev/odysseus · error · HTTPException
Invalid JSON
Error message
Invalid JSON
What it means
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.
Source
Thrown at routes/chat_routes.py:2487
restrict_owner=_user is not None,
include_legacy_owner=False,
)
]
# ------------------------------------------------------------------ #
# POST /api/rewrite — lightweight rewrite of last AI message (no tools)
# ------------------------------------------------------------------ #
@router.post("/api/rewrite")
async def rewrite_message(request: Request) -> StreamingResponse:
"""Rewrite the last AI message with an instruction (shorter/simpler/etc).
Unlike the full chat pipeline, this does NOT run the agent loop or tools.
It just asks the LLM to rewrite the given text.
"""
try:
body = await request.json()
except Exception:
raise HTTPException(400, "Invalid JSON")
session_id = body.get("session_id")
original_text = body.get("original_text", "")
instruction = body.get("instruction", "")
if not session_id or not original_text or not instruction:
raise HTTPException(400, "session_id, original_text, and instruction are required")
_verify_session_owner(request, session_id)
try:
sess = session_manager.get_session(session_id)
except (KeyError, SessionNotFoundError):
raise HTTPException(404, "Session not found")
messages = [
{"role": "system", "content": (
"You are rewriting a previous response. Follow the instruction exactly. "View on GitHub (pinned to f9235ebbf1)
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
Example fix
// before
fetch('/api/rewrite', {method:'POST', body: `session_id=${id}&instruction=shorter`})
// after
fetch('/api/rewrite', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({session_id: id, original_text: text, instruction: 'shorter'})}) Defensive patterns
Strategy: validation
Validate before calling
const body = JSON.stringify({session_id, original_text, instruction});
JSON.parse(body); // sanity round-trip
await fetch('/api/rewrite', {method:'POST', headers:{'Content-Type':'application/json'}, body}); Try / catch
try { await rewrite(...); } catch (e) { if (e.status === 400 && e.message === 'Invalid JSON') { console.error('body serialization bug', lastPayload); } } Prevention
- Always set Content-Type: application/json and JSON.stringify the body
- Don't reuse form-encoded helpers from chat_stream for this JSON endpoint
When it happens
Trigger: 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.
Common situations: 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.
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
- Invalid JSON: {e}
- session_id, original_text, and instruction are required
- Invalid JSON
- Expected a JSON object
- text is required
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/2c4987f0eef2768b.
Report an issue: GitHub.