odysseus-dev/odysseus · error · HTTPException

Failed to delete event

Error message

Failed to delete event

What it means

Generic HTTP 500 from DELETE /events/{uid}. The handler loads the event, optionally records a CalDAV delete tombstone and appends an EXDATE for occurrence deletes, deletes the row, commits, and may queue a CalDAV delete push. Any non-HTTP exception — DB commit failure, malformed stored recurrence_exdates JSON, tombstone insert error — is rolled back, logged as 'Failed to delete event: <e>', and returned as this 500.

Source

Thrown at routes/calendar_routes.py:1357

                if is_caldav:
                    ev.caldav_sync_pending = "update"
                db.commit()
                if is_caldav:
                    await _push_caldav_event_after_commit(owner, base_uid, "update")
                return {"ok": True, "scope": "occurrence", "exdate": key}
            if is_caldav:
                _record_caldav_delete_tombstone(db, ev, owner)
            db.delete(ev)
            db.commit()
            if is_caldav:
                await _push_caldav_event_after_commit(owner, base_uid, "delete")
            return {"ok": True}
        except HTTPException:
            raise
        except Exception as e:
            db.rollback()
            logger.error("Failed to delete event: %s", e)
            raise HTTPException(500, "Failed to delete event")
        finally:
            db.close()

    @router.post("/calendars")
    async def create_calendar(request: Request, name: str = "Imported", color: str = "#5b8abf"):
        owner = _require_user(request)
        _reserve_calendar_uploads(request, color)
        db = SessionLocal()
        try:
            cal = CalendarCal(
                id=str(uuid.uuid4()),
                owner=owner,
                name=name,
                color=color,
                source="local",
            )
            db.add(cal)
            db.commit()

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Check the server log ('Failed to delete event: <e>') for the underlying exception.
  2. If stored recurrence_exdates JSON is corrupt, repair or clear the value on that CalendarEvent row, then retry the delete.
  3. For 'database is locked', retry after concurrent writes finish or enable WAL.
  4. Guard the UI against double-submission of the delete button.
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm the event still exists to get the clean 404 instead of a 500 race
const ev = await api.get(`/events?start=...&end=...`); // or a single-event fetch
if (!eventExists(ev, uid)) return; // already gone

Try / catch

try { await api.del(`/events/${uid}`, {params: {scope}}); }
catch (e) {
  if (e.status === 404) return;            // already deleted
  if (e.status === 500) {                   // transient lock — one retry
    await sleep(300);
    return api.del(`/events/${uid}`, {params: {scope}});
  }
  throw e;
}

Prevention

When it happens

Trigger: Database locked at commit while CalDAV sync runs concurrently; recurrence_exdates JSON corrupt so _recurrence_exdates throws during an occurrence delete; tombstone write violating a constraint; DB file/schema unavailable.

Common situations: Double-delete racing itself (two rapid clicks both past the 404 point); corrupt exdate data from an older import; schema drift after upgrade; SQLite contention with the background CalDAV push worker.

Related errors


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