nextcloud/server · error · InvalidArgumentException

Calendar <$calendarId> is not writeable

Error message

Calendar <$calendarId> is not writeable

What it means

InvalidArgumentException thrown by occ dav:import-calendar (apps/dav/lib/Command/ImportCalendar.php:92) when CalendarImpl::isWritable() returns false. The import performs direct writes, so the target calendar must be writable - calendars with a read-only owner share or a backend flag preventing writes are rejected.

Source

Thrown at apps/dav/lib/Command/ImportCalendar.php:92

		$showCreated = $input->getOption('show-created');
		$showUpdated = $input->getOption('show-updated');
		$showSkipped = $input->getOption('show-skipped');
		$showErrors = $input->getOption('show-errors');

		if (!$this->userManager->userExists($userId)) {
			throw new InvalidArgumentException("User <$userId> not found.");
		}
		// retrieve calendar and evaluate if import is supported and writeable
		$calendars = $this->calendarManager->getCalendarsForPrincipal('principals/users/' . $userId, [$calendarId]);
		if ($calendars === []) {
			throw new InvalidArgumentException("Calendar <$calendarId> not found");
		}
		$calendar = $calendars[0];
		if (!$calendar instanceof CalendarImpl) {
			throw new InvalidArgumentException("Calendar <$calendarId> doesn't support this function");
		}
		if (!$calendar->isWritable()) {
			throw new InvalidArgumentException("Calendar <$calendarId> is not writeable");
		}
		if ($calendar->isDeleted()) {
			throw new InvalidArgumentException("Calendar <$calendarId> is deleted");
		}
		// construct options object
		$options = new CalendarImportOptions();
		$options->setSupersede($supersede);
		if ($errors !== null) {
			$options->setErrors($errors);
		}
		if ($validation !== null) {
			$options->setValidate($validation);
		}
		$options->setFormat($format);
		$options->setCounts(true);
		// evaluate if a valid location was given and is usable otherwise default to stdin
		if ($location !== null) {
			$stream = fopen($location, 'r');

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Import into a calendar the user owns with write access
  2. Ask the owner to reshare with can-edit, or run the import as the owning user
  3. Verify writability with a test PUT via CalDAV before the bulk import
Defensive patterns

Strategy: validation

Validate before calling

$calendar = $calendars[0];
if (!$calendar instanceof \OCA\DAV\CalDAV\CalendarImpl || !$calendar->isWritable()) {
    throw new RuntimeException('Import target must be writable');
}

Type guard

$isWritableCalendar = fn ($c): bool =>
    $c instanceof \OCA\DAV\CalDAV\CalendarImpl && $c->isWritable();

Prevention

When it happens

Trigger: occ dav:import-calendar alice <uri> ... where the calendar row/share marks it read-only (e.g. shared into the principal with writable=false, or backend permissions deny create).

Common situations: Importing into a calendar shared read-only by another user; calendars shared via publish links; permission changes made between discovery and import.

Related errors


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