odysseus-dev/odysseus · error · HTTPException
Failed to export ICS
Error message
Failed to export ICS
What it means
Generic HTTP 500 from GET /export/{cal_id}. The handler loads the calendar via _get_or_404_calendar (404 for missing/foreign ids, re-raised untouched), then serializes its events into an ICS payload and wraps it in a text/calendar Response. Any non-HTTP exception during serialization — an event field that breaks ICS generation, timezone rendering failure, or a DB error mid-query — is logged as 'Failed to export ICS: <e>' and returned as this 500.
Source
Thrown at routes/calendar_routes.py:1615
lines.append(f"RRULE:{ev.rrule}")
lines.append("END:VEVENT")
lines.append("END:VCALENDAR")
ics_data = "\r\n".join(lines)
download_name = _safe_ics_filename(cal.name)
return Response(
content=ics_data,
media_type="text/calendar",
headers={
"Content-Disposition": f'attachment; filename="{download_name}"',
"X-Content-Type-Options": "nosniff",
},
)
except HTTPException:
raise
except Exception as e:
logger.error("Failed to export ICS: %s", e)
raise HTTPException(500, "Failed to export ICS")
finally:
db.close()
@router.post("/quick-parse")
async def quick_parse(request: Request):
"""Parse a natural-language event description into structured fields.
Input: {"text": "lunch with sara friday 1pm downtown", "tz": "America/New_York"}
Output: {"ok": true, "event": {"summary", "dtstart", "dtend",
"all_day", "location", "description"}, "confidence": 0.0-1.0}
Anchored on the server's current date/time so phrases like
"tomorrow", "next Tuesday", "in 30 minutes" resolve correctly.
Uses the "utility" endpoint (small / fast model) to keep latency low.
"""
owner = _require_user(request)
from src.endpoint_resolver import resolve_endpoint
from src.llm_core import llm_call_asyncView on GitHub (pinned to f9235ebbf1)
Solutions
- Check the server log ('Failed to export ICS: <e>') for the failing event or field.
- Inspect the calendar's events (GET /events for that range) for the odd-one-out — often a single event with unusual datetime/timezone data; fix or delete it.
- Ensure tzdata is available in the runtime if the error names a timezone lookup.
- Verify cal_id comes from the caller's own GET /calendars list (a bad id gives 404, not this 500).
Defensive patterns
Strategy: try-catch
Validate before calling
const cals = await (await fetch('/calendars')).json();
if (!cals.calendars.some(c => c.href === calId)) throw new NotFound('no such calendar'); // clean 404 path
window.location = `/export/${calId}`; Try / catch
try { const blob = await api.get(`/export/${calId}`, {responseType: 'blob'}); saveBlob(blob); }
catch (e) {
if (e.status === 404) showError('Calendar not found');
else if (e.status === 500) showError('Export failed — server log names the bad event');
} Prevention
- Use cal_id values from the caller's own GET /calendars list.
- On 500, check the server log for the failing event and fix/delete it, then re-export.
- Keep tzdata available in the runtime so datetime serialization of stored events never fails.
When it happens
Trigger: An event with a stored datetime or timezone that the ICS writer cannot serialize (naive/aware mismatch, unknown TZID); a field containing characters the exporter cannot escape; database error while streaming the event rows; null in a column the export code assumes non-null.
Common situations: Exporting a calendar containing events created by an older version or by an import with edge-case data; tzdata missing in the deployment container; corrupt rows from a partially applied migration.
Related errors
- Failed to import ICS
- Invalid ICS file: {e}
- Failed to fetch document library: {e}
- Failed to delete calendar
- Failed to list calendars
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/348f98fb60b6c9e9.
Report an issue: GitHub.