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

  1. Ensure the request body includes a non-empty 'text' field: {"text": "meeting next friday at 3pm", "tz": "America/New_York"}
  2. Trim and check the input client-side before sending; disable the submit action while the textarea is blank
  3. 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

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


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/e945f54e12373c19. Report an issue: GitHub.