odysseus-dev/odysseus · error · HTTPException
Failed to update calendar
Error message
Failed to update calendar
What it means
Generic HTTP 500 from PUT /calendars/{cal_id}. The handler loads the calendar via _get_or_404_calendar (which itself raises 404 for missing/foreign calendars), applies optional name/color updates, and commits. Non-HTTP exceptions — commit failure, DB constraint, oversized values — are rolled back, logged as 'Failed to update calendar: <e>', and returned as this 500. The 404 path is re-raised untouched, so this error always means the update itself failed, not a bad id.
Source
Thrown at routes/calendar_routes.py:1402
@router.put("/calendars/{cal_id}")
async def update_calendar(request: Request, cal_id: str, name: str = None, color: str = None):
owner = _require_user(request)
_reserve_calendar_uploads(request, color)
db = SessionLocal()
try:
cal = _get_or_404_calendar(db, cal_id, owner)
if name is not None:
cal.name = name
if color is not None:
cal.color = color
db.commit()
return {"ok": True}
except HTTPException:
raise
except Exception as e:
db.rollback()
logger.error("Failed to update calendar: %s", e)
raise HTTPException(500, "Failed to update calendar")
finally:
db.close()
# Hard cap on ICS upload (ICS_MAX_BYTES, default 10 MB). Loading the whole
# file into memory is unavoidable with python-icalendar, so an unbounded
# upload would OOM.
@router.post("/import")
async def import_ics(request: Request, file: UploadFile = File(...), calendar_name: str = ""):
"""Import events from an .ics file (scoped to caller's account)."""
from icalendar import Calendar as iCal
owner = _require_user(request)
db = SessionLocal()
try:
content = await read_upload_limited(file, ICS_MAX_BYTES, "ICS file")
try:View on GitHub (pinned to f9235ebbf1)
Solutions
- Check the server log ('Failed to update calendar: <e>') for the concrete cause.
- Keep name/color short and well-formed (e.g. '#rrggbb' for color).
- For lock contention, retry once after other writes finish or enable SQLite WAL.
- Run schema migrations if the log reports a missing column.
Defensive patterns
Strategy: try-catch
Validate before calling
const patch = {};
if (name != null) patch.name = String(name).trim().slice(0, 100);
if (color != null && /^#[0-9a-fA-F]{6}$/.test(color)) patch.color = color;
await api.put(`/calendars/${calId}`, null, {params: patch}); Try / catch
try { await api.put(`/calendars/${calId}`, null, {params: {name, color}}); }
catch (e) {
if (e.status === 404) refreshCalendarList(); // calendar gone — resync ids
else if (e.status === 500) throw e; // check log 'Failed to update calendar'
else throw e;
} Prevention
- Send only the query params you are changing (name/color); omitted params are left as-is.
- Validate the color format client-side.
- Distinguish 404 (bad/foreign id) from 500 (update failure) — they need different handling.
When it happens
Trigger: Setting name or color to a value the DB column rejects (excessive length, null bytes); database locked at commit; schema mismatch after upgrade; a color string not matching a CHECK constraint if one exists.
Common situations: Renaming to a very long pasted string; color picker emitting an unexpected format; concurrent CalDAV sync holding the write lock; migration not run so a referenced column is missing.
Related errors
- Failed to delete calendar
- Failed to list calendars
- Failed to create calendar
- Failed to create document: {e}
- Failed to fetch document library: {e}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/f7bd1375809f36e8.
Report an issue: GitHub.