odysseus-dev/odysseus · error · HTTPException
text is required
Error message
text is required
What it means
Thrown by a calendar utility endpoint that parses natural-language date expressions using an LLM. The handler reads the JSON body and requires a non-empty 'text' field after stripping whitespace. If 'text' is missing, null, or blank, the request is rejected with HTTP 400 before any model call is made.
Source
Thrown at routes/calendar_routes.py:1641
Input: {"text": "lunch with sara friday 1pm downtown", "tz": "America/New_York"}
Output: {"ok": true, "event": {"summary", "dtstart", "dtend",
"all_day", "location", "description"}, "confidence": 0.0-1.0}
Anchored on the server's current date/time so phrases like
"tomorrow", "next Tuesday", "in 30 minutes" resolve correctly.
Uses the "utility" endpoint (small / fast model) to keep latency low.
"""
owner = _require_user(request)
from src.endpoint_resolver import resolve_endpoint
from src.llm_core import llm_call_async
from src.text_helpers import strip_think
import json as _json
import re as _re
body = await request.json()
text = (body.get("text") or "").strip()
if not text:
raise HTTPException(400, "text is required")
from src.user_time import (
clear_user_time_context,
current_datetime_prompt,
now_user_local,
set_user_tz_name,
set_user_tz_offset,
)
clear_user_time_context()
tz_hint = (body.get("tz") or "").strip()
if body.get("tz_offset") is not None:
set_user_tz_offset(body.get("tz_offset"))
if tz_hint:
set_user_tz_name(tz_hint)
url, model, headers = resolve_endpoint("utility", owner=owner or None)
if not url:
url, model, headers = resolve_endpoint("default", owner=owner or None)View on GitHub (pinned to f9235ebbf1)
Solutions
- Ensure the request body includes a non-empty 'text' field: {"text": "meeting next friday at 3pm", "tz": "America/New_York"}
- Trim and check the input client-side before sending; disable the submit action while the textarea is blank
- Verify the frontend field name matches 'text' exactly (not 'date_text', 'query', etc.)
Example fix
// before
fetch('/api/calendar/parse', {method:'POST', body: JSON.stringify({query: userInput})})
// after
if (!userInput.trim()) return;
fetch('/api/calendar/parse', {method:'POST', body: JSON.stringify({text: userInput.trim()})}) Defensive patterns
Strategy: validation
Validate before calling
const text = (userInput ?? '').trim();
if (!text) { showError('Enter a date expression to parse.'); return; }
await fetch(url, {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({text})}); Type guard
function isValidParsePayload(b: unknown): b is {text: string} {
return typeof b === 'object' && b !== null && typeof (b as any).text === 'string' && (b as any).text.trim().length > 0;
} Prevention
- Trim user input client-side and block blank submits
- Keep the payload field name 'text' in sync between frontend and this route
When it happens
Trigger: POST to the calendar date-parsing route with a JSON body lacking 'text', with 'text': null, or with 'text': " " (whitespace only). The check is (body.get("text") or "").strip() so falsy or blank values all trigger it.
Common situations: Frontend sends an empty input box submit; a form field named differently (e.g. 'query' or 'date_text') than the API expects; a null from an optional UI state variable serialized directly into the request body.
Related errors
- Invalid JSON: {e}
- session_id, original_text, and instruction are required
- Invalid remote_host — must be host or user@host, no SSH opti
- Invalid ssh_port
- Unknown wipe kind: {kind!r}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/e945f54e12373c19.
Report an issue: GitHub.