odysseus-dev/odysseus · error · HTTPException
Invalid request parameters
Error message
Invalid request parameters
What it means
Generic 400 raised when the request-shaping phase raises ValueError or pydantic ValidationError — i.e. the submitted parameters are well-formed JSON but semantically invalid. The original exception is swallowed, so the 400 text does not say which field failed.
Source
Thrown at routes/chat_routes.py:1105
_explicit_browser_intent = True
if chat_mode == "chat":
chat_mode = "agent"
auto_escalated = True
_workspace_agent_intent = False
logger.info("chat→agent auto-escalation: contextual browser/form follow-up")
if not workspace and isinstance(message, str):
_auto_workspace, _ = _resolve_workspace_from_message_path(request, message)
if _auto_workspace:
workspace = _auto_workspace
chat_mode = "agent"
auto_escalated = True
_workspace_agent_intent = True
allow_bash = "true"
logger.info("chat→agent auto-escalation: explicit path workspace=%s", workspace)
except SessionNotFoundError as e:
raise HTTPException(404, str(e))
except (ValueError, ValidationError):
raise HTTPException(400, "Invalid request parameters")
# ------------------------------------------------------------------ #
# Privilege gates that must fire BEFORE any LLM work / token spend.
# 1. allowed_models — reject if session.model isn't in the user's
# configured allowlist (empty list = "no restriction").
# 2. max_messages_per_day — count user-role ChatMessage rows owned
# by this user in the last UTC day; 429 if at/over the cap.
# Admins always have full privileges via get_privileges (returns
# ADMIN_PRIVILEGES wholesale) so this is a no-op for them.
_enforce_chat_privileges(request, sess)
# Ensure session has auth headers
resolve_session_auth(sess, session, owner=effective_user(request))
# Check for research_pending BEFORE mode persist overwrites it
do_research = str(use_research).lower() == "true"
if not do_research:
if get_session_mode(session) == 'research_pending':View on GitHub (pinned to f9235ebbf1)
Solutions
- Check server logs/stderr — the swallowed ValueError/ValidationError details are logged or traceable there; the response body alone won't say
- Diff the payload against the current request schema (chat_mode, preset_id, attachments, flags) and fix the offending field
- After a backend upgrade, refresh the client so option names/types match the new schema
Defensive patterns
Strategy: try-catch
Validate before calling
const ALLOWED_MODES = new Set(['chat','agent','research']);
if (chat_mode && !ALLOWED_MODES.has(chat_mode)) { fixMode(); return; } Type guard
function isValidChatOptions(o: any): boolean {
return (!o.chat_mode || ['chat','agent','research'].includes(o.chat_mode))
&& (!o.preset_id || typeof o.preset_id === 'string');
} Try / catch
try { await streamChat(...); } catch (e) { if (e.status === 400 && e.message === 'Invalid request parameters') { logPayloadForSchemaDiff(payload); } } Prevention
- Keep client option names/types in lockstep with the server schema after deploys
- Log the full payload when this 400 hits — the server hides the field name
When it happens
Trigger: POST /api/chat_stream with out-of-range or wrongly-typed options: invalid chat_mode, bad preset_id, malformed attachments metadata, or any enum/constraint pydantic rejects during coercion.
Common situations: Frontend updated to send new option values the backend schema doesn't accept; version skew between client and server after a deploy; hand-written payloads with wrong types (strings for booleans, etc.).
Related errors
- text is required
- Invalid JSON: {e}
- Invalid JSON
- session_id, original_text, and instruction are required
- Invalid draft payload: {exc}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/247e7572b4c49efe.
Report an issue: GitHub.