odysseus-dev/odysseus · error · ValueError
malformed compound UID: missing base before ::
Error message
malformed compound UID: missing base before ::
What it means
ValueError raised by _resolve_base_uid when the uid contains '::' but the base segment before it is empty, e.g. '::20260814'. The compound format is '{base_uid}::{date_suffix}'; an empty base has no resolvable series, so the helper refuses it.
Source
Thrown at routes/calendar_routes.py:147
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":
from src.caldav_sync import push_event_update
result = await push_event_update(owner, uid)
elif action == "delete":
from src.caldav_sync import push_event_delete
result = await push_event_delete(owner, uid)
if result and not result.get("ok") and not result.get("skipped"):View on GitHub (pinned to f9235ebbf1)
Solutions
- Fix the uid construction site to guarantee a non-empty base before appending '::'.
- Sanitize incoming uids at the API boundary: reject ones matching /^::/ with a 400.
- Repair corrupted rows in the events table rather than working around the ValueError.
Example fix
// before
const uid = `${base}::${date}`; // base may be ''
// after
if (!base) throw new Error('base uid required');
const uid = `${base}::${date}`; Defensive patterns
Strategy: type-guard
Validate before calling
const okCompound = (uid) => !uid.includes('::') || uid.split('::')[0].length > 0;
if (!okCompound(uid)) return badRequest('malformed uid'); Type guard
const isWellFormedUid = (u: string): boolean =>
u.length > 0 && !u.startsWith('::'); Try / catch
catch (e) { if (e instanceof ValueError && /malformed/.test(e.message)) { rejectPayload(); } } Prevention
- Never build compound uids without asserting the base segment is non-empty.
- Reject uids matching /^::/ at request validation time.
- Add a test for '${base}::${date}' construction with empty base.
When it happens
Trigger: Passing a malformed compound uid like '::2026-08-14' or ' ::x' (whitespace-only base) into recurrence resolution or an occurrence-edit endpoint.
Common situations: Client-side uid concatenation bug (base variable empty when building `${base}::${date}`); imported/corrupted CalDAV data with mangled UIDs; hand-crafted test payloads.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- empty uid
- 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/3567fed82ddd03fa.
Report an issue: GitHub.