{"record":{"id":"427135973718fefa","repo":"odysseus-dev/odysseus","slug":"failed-to-create-calendar","errorCode":null,"errorMessage":"Failed to create calendar","messagePattern":"Failed to create calendar","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"routes/calendar_routes.py","lineNumber":1380,"sourceCode":"    async def create_calendar(request: Request, name: str = \"Imported\", color: str = \"#5b8abf\"):\n        owner = _require_user(request)\n        _reserve_calendar_uploads(request, color)\n        db = SessionLocal()\n        try:\n            cal = CalendarCal(\n                id=str(uuid.uuid4()),\n                owner=owner,\n                name=name,\n                color=color,\n                source=\"local\",\n            )\n            db.add(cal)\n            db.commit()\n            return {\"ok\": True, \"id\": cal.id, \"name\": cal.name, \"color\": cal.color}\n        except Exception as e:\n            db.rollback()\n            logger.error(\"Failed to create calendar: %s\", e)\n            raise HTTPException(500, \"Failed to create calendar\")\n        finally:\n            db.close()\n\n    @router.put(\"/calendars/{cal_id}\")\n    async def update_calendar(request: Request, cal_id: str, name: str = None, color: str = None):\n        owner = _require_user(request)\n        _reserve_calendar_uploads(request, color)\n        db = SessionLocal()\n        try:\n            cal = _get_or_404_calendar(db, cal_id, owner)\n            if name is not None:\n                cal.name = name\n            if color is not None:\n                cal.color = color\n            db.commit()\n            return {\"ok\": True}\n        except HTTPException:\n            raise","sourceCodeStart":1362,"sourceCodeEnd":1398,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/calendar_routes.py#L1362-L1398","documentation":"Generic HTTP 500 from POST /calendars. The handler builds a CalendarCal row (uuid id, owner, name, color, source='local'), adds and commits it. Note this route has NO 'except HTTPException: raise' clause, but it also performs no _get_or_404 call, so in practice every failure is a genuine exception: DB error at commit, constraint violation, or an invalid color/name value rejected by the DB — logged as 'Failed to create calendar: <e>' and returned as this 500.","triggerScenarios":"Database locked or unavailable at commit; name/color exceeding column limits (very long names); NOT NULL/unique constraint on id colliding only in pathological cases; disk full.","commonSituations":"Creating a calendar while the CalDAV sync worker holds the SQLite write lock; schema not migrated so CalendarCal lacks expected columns; user pasting an extremely long calendar name from clipboard.","solutions":["Read the logged exception ('Failed to create calendar: <e>') to identify the constraint or DB error.","Truncate the calendar name to a sane length client-side before posting.","If 'database is locked', retry after concurrent writes complete or enable WAL.","Apply pending schema migrations if a column mismatch is reported."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const name = String(rawName).trim().slice(0, 100) || 'Imported';\nconst color = /^#[0-9a-fA-F]{6}$/.test(rawColor) ? rawColor : '#5b8abf';\nawait api.post('/calendars', null, {params: {name, color}});","typeGuard":null,"tryCatchPattern":"try { await api.post('/calendars', null, {params: {name, color}}); }\ncatch (e) {\n  if (e.status === 500) { /* server log 'Failed to create calendar' has root cause */ throw e; }\n  throw e;\n}","preventionTips":["Cap the calendar name length client-side before posting.","Send color as a #rrggbb string from the picker.","Retry once on 500 if the app uses SQLite — lock contention with sync workers is the usual cause."],"tags":["http-500","fastapi","database","sqlalchemy"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}