{"record":{"id":"22a0da4d5fffb8f1","repo":"nextcloud/server","slug":"calendar-is-a-subscription-not-writable-shared-o","errorCode":null,"errorMessage":"Calendar is a subscription, not writable, shared or deleted","messagePattern":"Calendar is a subscription, not writable, shared or deleted","errorType":"http","errorClass":"DavException","httpStatus":500,"severity":"error","filePath":"apps/dav/lib/CalDAV/DefaultCalendarValidator.php","lineNumber":26,"sourceCode":" */\n\nnamespace OCA\\DAV\\CalDAV;\n\nuse Sabre\\DAV\\Exception as DavException;\n\nclass DefaultCalendarValidator {\n\t/**\n\t * Check if a given Calendar node is suitable to be used as the default calendar for scheduling.\n\t *\n\t * @throws DavException If the calendar is not suitable to be used as the default calendar\n\t */\n\tpublic function validateScheduleDefaultCalendar(Calendar $calendar): void {\n\t\t// Sanity checks for a calendar that should handle invitations\n\t\tif ($calendar->isSubscription()\n\t\t\t|| !$calendar->canWrite()\n\t\t\t|| $calendar->isShared()\n\t\t\t|| $calendar->isDeleted()) {\n\t\t\tthrow new DavException('Calendar is a subscription, not writable, shared or deleted');\n\t\t}\n\n\t\t// Calendar must support VEVENTs\n\t\t$sCCS = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';\n\t\t$calendarProperties = $calendar->getProperties([$sCCS]);\n\t\tif (isset($calendarProperties[$sCCS])) {\n\t\t\t$supportedComponents = $calendarProperties[$sCCS]->getValue();\n\t\t} else {\n\t\t\t$supportedComponents = ['VJOURNAL', 'VTODO', 'VEVENT'];\n\t\t}\n\t\tif (!in_array('VEVENT', $supportedComponents, true)) {\n\t\t\tthrow new DavException('Calendar does not support VEVENT components');\n\t\t}\n\t}\n}\n","sourceCodeStart":8,"sourceCodeEnd":42,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/CalDAV/DefaultCalendarValidator.php#L8-L42","documentation":"DavException thrown by DefaultCalendarValidator::validateScheduleDefaultCalendar() when a Calendar node is unfit to be the default scheduling calendar. It rejects calendars that are webcal subscriptions (isSubscription()), not writable (canWrite() false, e.g. read-only share), shared (isShared()), or deleted/in trashbin (isDeleted()). Callers use it before storing IMip/scheduling invitations into the calendar.","triggerScenarios":"Passing a subscription, read-only shared, deleted, or otherwise non-writable Calendar to validateScheduleDefaultCalendar(); selecting such a calendar as scheduling default when an invite reply (IMip REPLY, accept/decline flow) arrives; trying to write scheduling objects into a calendar restored-preview from trashbin.","commonSituations":"User's default calendar was deleted so a fallback resolves to a shared/subscription calendar; admin moved users to read-only shares; automated tests that build Calendar fixtures without write permissions; calendar app picking the first calendar found which happens to be a webcal subscription.","solutions":["Pick a personal, writable, non-deleted calendar as the scheduling default before validating.","If the intended calendar is in the trashbin, restore it first and retry.","Unshare or switch to a calendar the principal owns with write access.","In code, pre-check $calendar->isSubscription() || !$calendar->canWrite() || $calendar->isShared() || $calendar->isDeleted() and fall back to creating a new personal calendar."],"exampleFix":"// before\n$validator->validateScheduleDefaultCalendar($calendar);\n\n// after\nif ($calendar->isSubscription() || !$calendar->canWrite() || $calendar->isShared() || $calendar->isDeleted()) {\n\t$calendar = $calendarManager->createCalendar($userId, 'personal', ['VEVENT']);\n}\n$validator->validateScheduleDefaultCalendar($calendar);","handlingStrategy":"validation","validationCode":"if ($calendar->isSubscription() || !$calendar->canWrite() || $calendar->isShared() || $calendar->isDeleted()) {\n    // not usable as scheduling default; pick or create a personal writable calendar\n    $calendar = $calendarManager->createCalendar($userId, 'personal', ['VEVENT']);\n}\n$validator->validateScheduleDefaultCalendar($calendar);","typeGuard":null,"tryCatchPattern":"try {\n    $validator->validateScheduleDefaultCalendar($calendar);\n} catch (\\OCA\\DAV\\Connector\\Sabre\\Exception\\DavException $e) {\n    // fall back to another calendar and retry validation\n}","preventionTips":["Filter candidate calendars by canWrite()/isDeleted()/isShared()/isSubscription() before choosing a scheduling default.","Restore trashed calendars before reusing them in scheduling flows.","Cover this in tests with a read-only share fixture."],"tags":["caldav","calendar","validation","scheduling","read-only","webcal"],"backgroundTag":"read-only-resource-write","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}