{"record":{"id":"4274daaf9fb30b5f","repo":"nextcloud/server","slug":"error-importing-calendar-data-one-or-more-objects","errorCode":null,"errorMessage":"Error importing calendar data: One or more objects discovered with no base component types","messagePattern":"Error importing calendar data: One or more objects discovered with no base component types","errorType":"validation","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"apps/dav/lib/CalDAV/Import/ImportService.php","lineNumber":280,"sourceCode":"\t\t$calendarId = $calendar->getKey();\n\t\t$calendarUri = $calendar->getUri();\n\t\t$principalUri = $calendar->getPrincipalUri();\n\t\tforeach ($generator($source, $options) as $key => $value) {\n\t\t\tif ($key === 'counts') {\n\t\t\t\tyield new ImportCountEvent(\n\t\t\t\t\tvevent: $value['VEVENT'] ?? 0,\n\t\t\t\t\tvtodo: $value['VTODO'] ?? 0,\n\t\t\t\t\tvjournal: $value['VJOURNAL'] ?? 0,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t$vObject = $value;\n\t\t\t$components = $vObject->getBaseComponents();\n\t\t\t// determine if the object has no base component types\n\t\t\tif (count($components) === 0) {\n\t\t\t\t$errorMessage = 'One or more objects discovered with no base component types';\n\t\t\t\tif ($options->getErrors() === $options::ERROR_FAIL) {\n\t\t\t\t\tthrow new InvalidArgumentException('Error importing calendar data: ' . $errorMessage);\n\t\t\t\t}\n\t\t\t\tyield new ImportObjectEvent(\n\t\t\t\t\tdisposition: ImportDisposition::Error,\n\t\t\t\t\tidentifier: null,\n\t\t\t\t\terrors: [$errorMessage]\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// determine if the object has more than one base component type\n\t\t\t// object can have multiple base components with the same uid\n\t\t\t// but we need to make sure they are of the same type\n\t\t\tif (count($components) > 1) {\n\t\t\t\t$type = $components[0]->name;\n\t\t\t\tforeach ($components as $entry) {\n\t\t\t\t\tif ($type !== $entry->name) {\n\t\t\t\t\t\t$errorMessage = 'One or more objects discovered with multiple base component types';\n\t\t\t\t\t\tif ($options->getErrors() === $options::ERROR_FAIL) {\n\t\t\t\t\t\t\tthrow new InvalidArgumentException('Error importing calendar data: ' . $errorMessage);","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/apps/dav/lib/CalDAV/Import/ImportService.php#L262-L298","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the .ics for VCALENDAR blocks without VEVENT/VTODO/VJOURNAL and remove or repair them before importing","Stream the import events instead of failing: keep errors below ERROR_FAIL and iterate the yielded ImportObjectEvent values, skipping disposition Error entries","Pre-validate the data with sabre/vobject Reader::read() and getBaseComponents() before calling import()"],"exampleFix":"// before\n$options = new CalendarImportOptions();\n// errors default to ERROR_FAIL -> import() throws on first bad object\n$service->import($source, $calendar, $options);\n\n// after\n$options->setErrors(CalendarImportOptions::ERROR_CONTINUE);\nforeach ($service->import($source, $calendar, $options) as $event) {\n    if ($event->disposition === ImportDisposition::Error) {\n        $this->logger->warning('Skipped object: ' . implode(', ', $event->errors));\n    }\n}","handlingStrategy":"validation","validationCode":"use Sabre\\VObject\\Reader;\n\n/** @throws InvalidArgumentException before ImportService does */\nfunction assertImportable(string $ics): void {\n    $v = Reader::read($ics);\n    if (count($v->getBaseComponents()) === 0) {\n        throw new InvalidArgumentException('no base component (VEVENT/VTODO/VJOURNAL)');\n    }\n}","typeGuard":"function hasBaseComponent(\\Sabre\\VObject\\Component\\VCalendar $v): bool {\n    return count($v->getBaseComponents()) > 0;\n}","tryCatchPattern":"try {\n    foreach ($service->import($source, $calendar, $options) as $event) {}\n} catch (\\InvalidArgumentException $e) {\n    // 'Error importing calendar data: ...' -> fix source data or relax error mode\n}","preventionTips":["Run exports through a lint step that requires one base component per VCALENDAR block","Prefer event-streaming error mode (below ERROR_FAIL) for user-supplied files so one bad object does not abort everything","Log the yielded ImportObjectEvent Error entries to report exactly which objects were skipped"],"tags":["caldav","icalendar","import","nextcloud","php","sabre-vobject"],"backgroundTag":"icalendar-import-validation","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}