nextcloud / nextcloud/server

Federated calendar sync deletion crashes in CalDavBackend with CachedCalendarObjectDeletedEvent TypeError

Open Beginner friendly
#61,290 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

0. Needs triage 33-feedback bug feature: caldav feature: federation
Dominant language
PHP
Stars
36.9k
Forks
5.2k
Avg merge
2d 3h
Merged PRs (30d)
713

Description

Steps to reproduce
  1. Run Nextcloud 33.0.5 with at least one federated calendar in oc_calendars_federated.
  2. Let OCA\DAV\BackgroundJob\FederatedCalendarPeriodicSyncJob sync a remote calendar where the sync report contains deleted objects.
  3. The job calls FederatedCalendarSyncService::syncOne(), which calls:
$this->backend->deleteCalendarObject(
    $calendar->getId(),
    $objectUri,
    CalDavBackend::CALENDAR_TYPE_FEDERATED,
    true
);
Expected behaviour

Federated-calendar object deletion should complete without trying to look up a calendar subscription.

Actual behaviour

The background job fails with a TypeError because CalDavBackend::deleteCalendarObject() treats every non-CALENDAR_TYPE_CALENDAR object as a calendar subscription deletion:

if ($calendarType === self::CALENDAR_TYPE_CALENDAR) {
    ...
} else {
    $subscriptionRow = $this->getSubscriptionById($calendarId);

    $this->dispatcher->dispatchTyped(new CachedCalendarObjectDeletedEvent($calendarId, $subscriptionRow, [], $data));
}

For CALENDAR_TYPE_FEDERATED (2), getSubscriptionById($calendarId) returns null, and CachedCalendarObjectDeletedEvent requires an array for $subscriptionData.

Sanitized stack trace excerpt:

Error while running background job OCA\DAV\BackgroundJob\FederatedCalendarPeriodicSyncJob

TypeError: OCA\DAV\Events\CachedCalendarObjectDeletedEvent::__construct():
Argument #2 ($subscriptionData) must be of type array, null given,
called in apps/dav/lib/CalDAV/CalDavBackend.php on line 1588

#0 apps/dav/lib/CalDAV/CalDavBackend.php(1588): OCA\DAV\Events\CachedCalendarObjectDeletedEvent->__construct()
#1 lib/public/AppFramework/Db/TTransactional.php(45): OCA\DAV\CalDAV\CalDavBackend->{closure:...}()
#2 apps/dav/lib/CalDAV/CalDavBackend.php(1564): OCA\DAV\CalDAV\CalDavBackend->atomic()
#3 apps/dav/lib/CalDAV/Federation/FederatedCalendarSyncService.php(122): OCA\DAV\CalDAV\CalDavBackend->deleteCalendarObject()
#4 apps/dav/lib/BackgroundJob/FederatedCalendarPeriodicSyncJob.php(47): OCA\DAV\CalDAV\Federation\FederatedCalendarSyncService->syncOne()
#5 lib/public/BackgroundJob/Job.php(50): OCA\DAV\BackgroundJob\FederatedCalendarPeriodicSyncJob->run()
#6 lib/public/BackgroundJob/TimedJob.php(85): OCP\BackgroundJob\Job->start()
#7 core/Service/CronService.php(176): OCP\BackgroundJob\TimedJob->start()
#8 core/Service/CronService.php(98): OC\Core\Service\CronService->runCli()
#9 cron.php(52): OC\Core\Service\CronService->run()
Diagnosis

This does not appear to be orphaned subscription data in the database. On the affected instance:

calendarobjects grouped by calendartype:
  calendartype=0 count=564
  calendartype=2 count=1210

orphan cached subscription objects:
  calendartype=1 objects without calendarsubscriptions row = 0

federated calendars:
  2 rows in oc_calendars_federated

The error path is therefore the federated delete branch being routed into the cached-subscription event branch.

createCalendarObject() and updateCalendarObject() already distinguish the three cases:

if ($calendarType === self::CALENDAR_TYPE_CALENDAR) {
    ...
} elseif ($calendarType === self::CALENDAR_TYPE_SUBSCRIPTION) {
    ...
} elseif ($calendarType === self::CALENDAR_TYPE_FEDERATED) {
    // TODO: implement custom event for federated calendars
}

deleteCalendarObject() appears to need the same structure.

Suggested fix

Change the delete branch from else to elseif ($calendarType === self::CALENDAR_TYPE_SUBSCRIPTION), and add an explicit no-op CALENDAR_TYPE_FEDERATED branch until there is a dedicated federated-calendar deleted event:

if ($calendarType === self::CALENDAR_TYPE_CALENDAR) {
    $calendarRow = $this->getCalendarById($calendarId);
    $shares = $this->getShares($calendarId);

    $this->dispatcher->dispatchTyped(new CalendarObjectDeletedEvent($calendarId, $calendarRow, $shares, $data));
} elseif ($calendarType === self::CALENDAR_TYPE_SUBSCRIPTION) {
    $subscriptionRow = $this->getSubscriptionById($calendarId);

    $this->dispatcher->dispatchTyped(new CachedCalendarObjectDeletedEvent($calendarId, $subscriptionRow, [], $data));
} elseif ($calendarType === self::CALENDAR_TYPE_FEDERATED) {
    // TODO: implement custom event for federated calendars
}

I tested that local change on the affected instance by forcing the previously failing job with:

occ background-job:execute --force-execute <job-id>

After the local patch, the job completed, the federated sync token advanced, and cached federated objects dropped from 1210 to 1200, indicating that the remote deletions were processed.

Server configuration
  • Nextcloud version: 33.0.5.1 / version string 33.0.5
  • Database: PostgreSQL
  • Background jobs: cron
  • App/code path involved: apps/dav/lib/CalDAV/CalDavBackend.php, apps/dav/lib/CalDAV/Federation/FederatedCalendarSyncService.php, apps/dav/lib/BackgroundJob/FederatedCalendarPeriodicSyncJob.php

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in apps/dav/lib/CalDAV/CalDavBackend.php at deleteCalendarObject(), then compare its calendar-type handling with createCalendarObject() and updateCalendarObject(). Reproduce or force the job through FederatedCalendarSyncService::syncOne() using the mentioned occ background-job command; done means federated deletions complete without the TypeError and the sync token advances.

Written by the indexing model from the issue text.

Assessment

Tech stack
php
Domain
backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.