nextcloud/server · error · CalendarException

Could not create new calendar event: {message}

Error message

Could not create new calendar event: {message}

What it means

Thrown as OCA\DAV\CalDAV\CalendarException by CalendarImpl::createFromStringInServer() when the embedded sabre/dav server rejects $server->createFile() with a Conflict while writing a new event object. The original sabre Conflict message is appended, so the CalendarException text is a wrapper around the underlying DAV conflict reason. It surfaces through the public ICalendar API methods createFromString() and createFromStringMinimal().

Source

Thrown at apps/dav/lib/CalDAV/CalendarImpl.php:223

			throw new CalendarException('Could not write to calendar as URI parameter is missing');
		}

		// Build full calendar path
		[, $user] = uriSplit($this->calendar->getPrincipalURI());
		$fullCalendarFilename = sprintf('calendars/%s/%s/%s', $user, $this->calendarInfo['uri'], $name);

		// Force calendar change URI
		/** @var Schedule\Plugin $schedulingPlugin */
		$schedulingPlugin = $server->getPlugin('caldav-schedule');
		$schedulingPlugin->setPathOfCalendarObjectChange($fullCalendarFilename);

		$stream = fopen('php://memory', 'rb+');
		fwrite($stream, $calendarData);
		rewind($stream);
		try {
			$server->createFile($fullCalendarFilename, $stream);
		} catch (Conflict $e) {
			throw new CalendarException('Could not create new calendar event: ' . $e->getMessage(), 0, $e);
		} finally {
			fclose($stream);
		}
	}

	#[\Override]
	public function createFromString(string $name, string $calendarData): void {
		$server = new EmbeddedCalDavServer(false);
		$this->createFromStringInServer($name, $calendarData, $server->getServer());
	}

	#[\Override]
	public function createFromStringMinimal(string $name, string $calendarData): void {
		$server = new InvitationResponseServer(false);
		$this->createFromStringInServer($name, $calendarData, $server->getServer());
	}

	/**

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Generate a unique object name per event (e.g. the event UID plus a random suffix) before calling createFromString().
  2. Before creating, check whether an object with that name already exists (calendarQuery/search on the ICalendar or the CalDAV backend) and update instead of create.
  3. Catch CalendarException around createFromString(), inspect the chained Conflict via getPrevious(), and decide skip/update/rename on collision.
  4. For imports, track which UIDs were already written so re-runs are idempotent.

Example fix

// before
$calendar->createFromString('event.ics', $calendarData);

// after
$name = $eventUid . '-' . bin2hex(random_bytes(4)) . '.ics';
try {
	$calendar->createFromString($name, $calendarData);
} catch (CalendarException $e) {
	// object name collision or scheduling conflict; inspect $e->getPrevious()
	$logger->warning('Event create failed: ' . $e->getMessage());
}
Defensive patterns

Strategy: try-catch

Validate before calling

// derive a collision-free name before creating
$objectName = $eventUid . '.ics';
$existing = $calendar->search('', ['UID'], ['uid' => $eventUid]); // or calendarQuery via backend
if ($existing !== []) {
    $objectName = $eventUid . '-' . bin2hex(random_bytes(4)) . '.ics';
}

Try / catch

try {
    $calendar->createFromString($name, $calendarData);
} catch (\OCA\DAV\CalDAV\CalendarException $e) {
    if ($e->getPrevious() instanceof \Sabre\DAV\Exception\Conflict) {
        // name collision or scheduling conflict -> rename and retry once, or update existing
    }
    throw $e;
}

Prevention

When it happens

Trigger: Calling $calendar->createFromString($name, $calendarData) (or createFromStringMinimal) on an OCA\DAV\CalDAV\CalendarImpl when an object with the same filename already exists under calendars/<user>/<calendarUri>/<name>, or when the CalDAV scheduling/plugin layer reports a conflict during the PUT into the embedded server. Typical from calendar import scripts that reuse a fixed object name or re-run after a partial failure.

Common situations: Bulk iCalendar imports that derive the object name from a UID and hit the same UID twice; retrying an import after a timeout without skipping already-created events; concurrent requests creating the same event name; testing event creation in a loop with a hardcoded '.ics' filename.

Related errors


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