odysseus-dev/odysseus · error · HTTPException

Failed to create event

Error message

Failed to create event

What it means

Generic HTTP 500 from POST /events. The handler resolves the calendar, parses dtstart/dtend with timezone detection, builds a CalendarEvent row, commits, and optionally queues a CalDAV push. Any non-HTTP exception in that path — unparseable datetime despite the tz-detecting parser, DB failure at commit, constraint violation — is rolled back, logged as 'Failed to create event: <e>', and surfaced as this 500.

Source

Thrown at routes/calendar_routes.py:1263

                dtstart=dtstart,
                dtend=dtend,
                all_day=data.all_day,
                is_utc=_is_utc and not data.all_day,
                rrule=data.rrule or "",
                color=data.color or None,
                caldav_sync_pending="create" if cal.source == "caldav" else None,
            )
            db.add(ev)
            db.commit()
            if cal.source == "caldav":
                await _push_caldav_event_after_commit(owner, uid, "create")
            return {"ok": True, "uid": uid}
        except HTTPException:
            raise
        except Exception as e:
            db.rollback()
            logger.error("Failed to create event: %s", e)
            raise HTTPException(500, "Failed to create event")
        finally:
            db.close()

    @router.put("/events/{uid}")
    async def update_event(request: Request, uid: str, data: EventUpdate):
        owner = _require_user(request)
        _reserve_calendar_uploads(request, data.color, data.description, data.location)
        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)
            if data.summary is not None:
                ev.summary = data.summary
            if data.description is not None:
                ev.description = data.description

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Check the server log ('Failed to create event: <e>') for the underlying exception.
  2. Send dtstart/dtend as ISO 8601 ('2026-05-13T10:00:00' or with offset/Z).
  3. If the log shows a constraint or missing column, run schema migrations.
  4. If 'database is locked', retry once after concurrent writes settle or move off contended SQLite.

Example fix

// before
body: JSON.stringify({summary: 'Lunch', dtstart: '05/13/2026 1:00 PM'})

// after
body: JSON.stringify({summary: 'Lunch', dtstart: '2026-05-13T13:00:00', dtend: '2026-05-13T14:00:00'})
Defensive patterns

Strategy: validation

Validate before calling

function toIsoOrNull(v) {
  const d = new Date(v);
  return isNaN(d.getTime()) ? null : d.toISOString();
}
const dtstart = toIsoOrNull(payload.dtstart);
if (!dtstart) throw new Error('dtstart must be a valid date');
await api.post('/events', {...payload, dtstart, dtend: toIsoOrNull(payload.dtend) ?? undefined});

Try / catch

try { await api.post('/events', payload); }
catch (e) {
  if (e.status === 500) { /* check server log 'Failed to create event' for the field */ throw e; }
  throw e;
}

Prevention

When it happens

Trigger: dtstart/dtstart format the parser cannot handle at all (e.g. '13/45/2026', empty string after EventCreate validation); dtend earlier-format mismatch causing a comparison error; database locked at commit; NOT NULL constraint hit for a field the client omitted; failure scheduling the CalDAV push.

Common situations: Client sending locale-formatted dates (MM/DD/YYYY) instead of ISO 8601; SQLite write contention with the sync worker; schema drift after upgrading without migrating; all-day event posted with dtend but no dtstart semantics the model expects.

Related errors


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