nextcloud/server · error · DavException

Calendar is a subscription, not writable, shared or deleted

Error message

Calendar is a subscription, not writable, shared or deleted

What it means

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.

Source

Thrown at apps/dav/lib/CalDAV/DefaultCalendarValidator.php:26

 */

namespace OCA\DAV\CalDAV;

use Sabre\DAV\Exception as DavException;

class DefaultCalendarValidator {
	/**
	 * Check if a given Calendar node is suitable to be used as the default calendar for scheduling.
	 *
	 * @throws DavException If the calendar is not suitable to be used as the default calendar
	 */
	public function validateScheduleDefaultCalendar(Calendar $calendar): void {
		// Sanity checks for a calendar that should handle invitations
		if ($calendar->isSubscription()
			|| !$calendar->canWrite()
			|| $calendar->isShared()
			|| $calendar->isDeleted()) {
			throw new DavException('Calendar is a subscription, not writable, shared or deleted');
		}

		// Calendar must support VEVENTs
		$sCCS = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
		$calendarProperties = $calendar->getProperties([$sCCS]);
		if (isset($calendarProperties[$sCCS])) {
			$supportedComponents = $calendarProperties[$sCCS]->getValue();
		} else {
			$supportedComponents = ['VJOURNAL', 'VTODO', 'VEVENT'];
		}
		if (!in_array('VEVENT', $supportedComponents, true)) {
			throw new DavException('Calendar does not support VEVENT components');
		}
	}
}

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Pick a personal, writable, non-deleted calendar as the scheduling default before validating.
  2. If the intended calendar is in the trashbin, restore it first and retry.
  3. Unshare or switch to a calendar the principal owns with write access.
  4. In code, pre-check $calendar->isSubscription() || !$calendar->canWrite() || $calendar->isShared() || $calendar->isDeleted() and fall back to creating a new personal calendar.

Example fix

// before
$validator->validateScheduleDefaultCalendar($calendar);

// after
if ($calendar->isSubscription() || !$calendar->canWrite() || $calendar->isShared() || $calendar->isDeleted()) {
	$calendar = $calendarManager->createCalendar($userId, 'personal', ['VEVENT']);
}
$validator->validateScheduleDefaultCalendar($calendar);
Defensive patterns

Strategy: validation

Validate before calling

if ($calendar->isSubscription() || !$calendar->canWrite() || $calendar->isShared() || $calendar->isDeleted()) {
    // not usable as scheduling default; pick or create a personal writable calendar
    $calendar = $calendarManager->createCalendar($userId, 'personal', ['VEVENT']);
}
$validator->validateScheduleDefaultCalendar($calendar);

Try / catch

try {
    $validator->validateScheduleDefaultCalendar($calendar);
} catch (\OCA\DAV\Connector\Sabre\Exception\DavException $e) {
    // fall back to another calendar and retry validation
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17). Data as JSON: /api/errors/22a0da4d5fffb8f1. Report an issue: GitHub.