odysseus-dev/odysseus · warning · HTTPException
Calendar not found
Error message
Calendar not found
What it means
HTTP 404 raised by the calendar helper _get_or_404_calendar when db.query(CalendarCal).filter(id == cal_id).first() finds no row. Every calendar route funnels through this helper, so an unknown or malformed calendar id yields 404 regardless of ownership.
Source
Thrown at routes/calendar_routes.py:86
def _require_user(request: Request) -> str:
"""Return the authenticated user. Uses require_user so AUTH_ENABLED=false
and single-user mode both work: require_user returns "" when auth is
disabled or unconfigured, and only raises 401 when auth is configured but
the caller is unauthenticated. Falls back to FALLBACK_OWNER for calendar
writes so data isn't stored under an empty owner in single-user mode."""
user = require_user(request)
if user:
return user
# require_user returned "" — auth is off or unconfigured (single-user).
# Use FALLBACK_OWNER so calendar rows have a stable owner for filtering.
return FALLBACK_OWNER
def _get_or_404_calendar(db, cal_id: str, owner: str) -> CalendarCal:
cal = db.query(CalendarCal).filter(CalendarCal.id == cal_id).first()
if not cal:
raise HTTPException(404, "Calendar not found")
# Tighten the legacy null-owner gate (v2 review HIGH-12): if the
# caller is authenticated AND the calendar's owner is null OR
# belongs to a different user, treat it as not-found. The previous
# rule (`if cal.owner and cal.owner != owner`) silently allowed any
# authenticated user to read/edit any calendar with owner=None.
if owner and (cal.owner is None or cal.owner != owner):
raise HTTPException(404, "Calendar not found")
return cal
def _get_or_404_event(db, uid: str, owner: str) -> CalendarEvent:
ev = db.query(CalendarEvent).join(CalendarCal).filter(CalendarEvent.uid == uid).first()
if not ev:
raise HTTPException(404, "Event not found")
cal = ev.calendar
if owner and cal and (cal.owner is None or cal.owner != owner):
raise HTTPException(404, "Event not found")
return evView on GitHub (pinned to f9235ebbf1)
Solutions
- Re-fetch the calendar list (the collection route) and use a current id.
- Treat 404 as 'deleted elsewhere' and refresh local state rather than retrying.
- If the calendar should exist, verify the DB the app points at is the expected one.
Defensive patterns
Strategy: validation
Validate before calling
const ids = new Set((await listCalendars()).map(c => c.id));
if (!ids.has(calId)) throw new Error('calendar deleted — refresh'); Try / catch
catch (e) { if (e.status === 404) { dropLocalCalendar(calId); } else throw e; } Prevention
- Sync calendar ids from the server before operations on possibly-stale data.
- On 404 remove the calendar from local cache instead of retrying.
When it happens
Trigger: Any /api/calendar route taking a cal_id that does not exist in the calendars table: deleted calendar, stale id from an old client, or a typo in the path.
Common situations: Client caches a calendar list and uses an id deleted elsewhere; DB reset/restore dropped rows; two devices out of sync after offline edits.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/adb25e060fc56718.
Report an issue: GitHub.