odysseus-dev/odysseus · error · HTTPException
Failed to update event
Error message
Failed to update event
What it means
Generic HTTP 500 from PUT /events/{uid}. After loading the event via _get_or_404_event and applying field updates (with datetime re-parsing for dtstart/dtend), the handler commits and may queue a CalDAV update push. Any non-HTTP exception — datetime parse failure, DB commit error, constraint violation — is rolled back, logged as 'Failed to update event: <e>', and returned as this 500. A missing/foreign event gives 404, not this error.
Source
Thrown at routes/calendar_routes.py:1315
if data.all_day:
ev.is_utc = False # all-day stays date-only
if data.rrule is not None:
ev.rrule = data.rrule
if data.color is not None:
ev.color = data.color if data.color else None
is_caldav = ev.calendar and ev.calendar.source == "caldav"
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}
except HTTPException:
raise
except Exception as e:
db.rollback()
logger.error("Failed to update event: %s", e)
raise HTTPException(500, "Failed to update event")
finally:
db.close()
@router.delete("/events/{uid}")
async def delete_event(request: Request, uid: str, scope: str = "series"):
owner = _require_user(request)
try:
base_uid = _resolve_base_uid(uid)
except ValueError as e:
raise HTTPException(400, str(e))
db = SessionLocal()
try:
ev = _get_or_404_event(db, base_uid, owner)
is_occurrence_delete = scope in {"occurrence", "instance"} and "::" in uid and bool(ev.rrule)
is_caldav = ev.calendar and ev.calendar.source == "caldav"
if is_occurrence_delete:
key = _occurrence_exdate_key(uid, ev)
if not key:View on GitHub (pinned to f9235ebbf1)
Solutions
- Read the logged exception ('Failed to update event: <e>') to pinpoint the field or DB operation failing.
- Send dtstart/dtend in ISO 8601 format when updating times.
- If the log shows lock contention, retry the update after concurrent sync/write activity completes.
- Run pending migrations if a column mismatch is reported.
Defensive patterns
Strategy: try-catch
Validate before calling
// only send changed fields, with ISO datetimes
const patch = {};
if (changed.summary) patch.summary = changed.summary;
if (changed.dtstart) { const d = new Date(changed.dtstart); if (!isNaN(d)) patch.dtstart = d.toISOString(); }
await api.put(`/events/${uid}`, patch); Try / catch
try { await api.put(`/events/${uid}`, patch); }
catch (e) {
if (e.status === 500) { /* server log 'Failed to update event' names the field/op */ throw e; }
if (e.status === 404) { /* event deleted elsewhere */ refreshCalendar(); }
else throw e;
} Prevention
- Send only modified fields — smaller payloads expose fewer parse paths.
- Use ISO 8601 for any datetime field you update.
- Distinguish 404 (event gone) from 500 (update failed) in error handling; they need different client responses.
When it happens
Trigger: dtstart/dtstart payload in a format _parse_dt_pair cannot handle; setting a field to a type the DB column rejects; database locked at commit; rrule/recurrence_exdates update producing invalid JSON; failure during the post-commit CalDAV push path.
Common situations: Client sending locale-formatted or empty datetimes on edit; concurrent edit from CalDAV sync colliding at commit; schema drift after an upgrade; editing an imported event whose stored fields interact badly with the update path.
Related errors
- Failed to create event
- Failed to delete calendar
- Failed to list calendars
- Failed to list events
- Failed to delete event
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/79b5fdbdf25de5d1.
Report an issue: GitHub.