nextcloud/server · error · InvalidArgumentException

Error importing calendar data: One or more objects discovere

Error message

Error importing calendar data: One or more objects discovered with no base component types

What it means

Thrown by Nextcloud's calendar ImportService when an imported calendar object (a VCALENDAR block) contains no base component (no VEVENT, VTODO or VJOURNAL) and the error mode is CalendarImportOptions::ERROR_FAIL (the default). The stream parser hands the service a VCalendar whose getBaseComponents() returns an empty array, so the object cannot be stored as a calendar object. With a non-failing error mode nothing is thrown; instead an ImportObjectEvent with disposition Error is yielded.

Source

Thrown at apps/dav/lib/CalDAV/Import/ImportService.php:280

		$calendarId = $calendar->getKey();
		$calendarUri = $calendar->getUri();
		$principalUri = $calendar->getPrincipalUri();
		foreach ($generator($source, $options) as $key => $value) {
			if ($key === 'counts') {
				yield new ImportCountEvent(
					vevent: $value['VEVENT'] ?? 0,
					vtodo: $value['VTODO'] ?? 0,
					vjournal: $value['VJOURNAL'] ?? 0,
				);
				continue;
			}
			$vObject = $value;
			$components = $vObject->getBaseComponents();
			// determine if the object has no base component types
			if (count($components) === 0) {
				$errorMessage = 'One or more objects discovered with no base component types';
				if ($options->getErrors() === $options::ERROR_FAIL) {
					throw new InvalidArgumentException('Error importing calendar data: ' . $errorMessage);
				}
				yield new ImportObjectEvent(
					disposition: ImportDisposition::Error,
					identifier: null,
					errors: [$errorMessage]
				);
				continue;
			}
			// determine if the object has more than one base component type
			// object can have multiple base components with the same uid
			// but we need to make sure they are of the same type
			if (count($components) > 1) {
				$type = $components[0]->name;
				foreach ($components as $entry) {
					if ($type !== $entry->name) {
						$errorMessage = 'One or more objects discovered with multiple base component types';
						if ($options->getErrors() === $options::ERROR_FAIL) {
							throw new InvalidArgumentException('Error importing calendar data: ' . $errorMessage);

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Inspect the .ics for VCALENDAR blocks without VEVENT/VTODO/VJOURNAL and remove or repair them before importing
  2. Stream the import events instead of failing: keep errors below ERROR_FAIL and iterate the yielded ImportObjectEvent values, skipping disposition Error entries
  3. Pre-validate the data with sabre/vobject Reader::read() and getBaseComponents() before calling import()

Example fix

// before
$options = new CalendarImportOptions();
// errors default to ERROR_FAIL -> import() throws on first bad object
$service->import($source, $calendar, $options);

// after
$options->setErrors(CalendarImportOptions::ERROR_CONTINUE);
foreach ($service->import($source, $calendar, $options) as $event) {
    if ($event->disposition === ImportDisposition::Error) {
        $this->logger->warning('Skipped object: ' . implode(', ', $event->errors));
    }
}
Defensive patterns

Strategy: validation

Validate before calling

use Sabre\VObject\Reader;

/** @throws InvalidArgumentException before ImportService does */
function assertImportable(string $ics): void {
    $v = Reader::read($ics);
    if (count($v->getBaseComponents()) === 0) {
        throw new InvalidArgumentException('no base component (VEVENT/VTODO/VJOURNAL)');
    }
}

Type guard

function hasBaseComponent(\Sabre\VObject\Component\VCalendar $v): bool {
    return count($v->getBaseComponents()) > 0;
}

Try / catch

try {
    foreach ($service->import($source, $calendar, $options) as $event) {}
} catch (\InvalidArgumentException $e) {
    // 'Error importing calendar data: ...' -> fix source data or relax error mode
}

Prevention

When it happens

Trigger: Calling ImportService::import() with a format of ical/jcal/xcal on data where a VCALENDAR wrapper only holds a VTIMEZONE, a VALARM, a custom X- component, or nothing at all, while options->getErrors() === CalendarImportOptions::ERROR_FAIL.

Common situations: Importing .ics exports from other clients that emit standalone VTIMEZONE blocks; hand-edited or concatenated .ics files where object boundaries are broken; an export where all real components were removed but empty wrappers remain.

Related errors


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