odysseus-dev/odysseus · error · ValueError
empty uid
Error message
empty uid
What it means
ValueError('empty uid') raised by _resolve_base_uid when called with an empty (or None-after-truthiness) uid string. This helper splits compound recurrence uids of the form '{base}::{date}' and requires a non-empty input. It is an internal invariant violation, not a user-facing HTTP error, and typically surfaces as a 500 unless caught upstream.
Source
Thrown at routes/calendar_routes.py:141
def _safe_ics_filename(name: str) -> str:
"""Return a conservative .ics filename safe for Content-Disposition."""
stem = name if isinstance(name, str) else ""
stem = re.sub(r"[^A-Za-z0-9._-]", "_", stem).strip("._-")
if not stem:
stem = "calendar"
return f"{stem[:128]}.ics"
def _resolve_base_uid(uid: str) -> str:
"""Extract the base series UID from a compound occurrence UID.
Compound UIDs have the form ``{base_uid}::{date_suffix}``.
For plain UIDs (no ``::``), returns the UID unchanged.
"""
if not uid:
raise ValueError("empty uid")
idx = uid.find("::")
if idx == -1:
return uid # plain UID — no suffix
base = uid[:idx]
if not base:
raise ValueError("malformed compound UID: missing base before ::")
return base
async def _push_caldav_event_after_commit(owner: str, uid: str, action: str):
"""Best-effort CalDAV write-through. Local writes stay authoritative if
the remote server is unreachable; pending flags let /sync retry later."""
try:
result = {"ok": True}
if action == "create":
from src.caldav_sync import push_event_create
result = await push_event_create(owner, uid)
elif action == "update":View on GitHub (pinned to f9235ebbf1)
Solutions
- Generate a uid before saving events (uuid4 or the app's uid generator) so the helper never sees an empty string.
- Validate uid presence at the route boundary and return 400 before reaching recurrence logic.
- If seen in logs as 500, trace the caller passing the empty uid.
Example fix
# before
event = {"uid": body.get("uid", ""), "title": ...}
# after
import uuid
event = {"uid": (body.get("uid") or str(uuid.uuid4())).strip(), "title": ...} Defensive patterns
Strategy: type-guard
Validate before calling
if (!uid || !uid.trim()) return badRequest('uid is required'); Type guard
const hasUid = (e: {uid?: unknown}): e is {uid: string} =>
typeof e.uid === 'string' && e.uid.trim().length > 0; Try / catch
try { base = _resolveBaseUid(uid); } catch (e) { /* ValueError: reject payload with 400, don't 500 */ } Prevention
- Always generate a uid (uuid4) when creating events.
- Validate uid non-empty at the API boundary so this invariant error never reaches the helper.
- Treat an uncaught ValueError here as a 500-class bug in the caller, not user input.
When it happens
Trigger: Calling _resolve_base_uid('') — e.g. an event payload with uid: '' or a missing uid field flowing into recurrence handling; programmatic callers passing None.
Common situations: Client submits an event without generating a uid; a sync/import path leaves uid empty; malformed CalDAV data with empty UID components.
Related errors
- malformed compound UID: missing base before ::
- text is required
- d && d.detail ? d.detail : ('HTTP ' + res.status)
- result.detail || 'Failed to rename session'
- Invalid backup file: ' + e.message
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/2f17182628a3239d.
Report an issue: GitHub.