nextcloud / nextcloud/server

[Bug]: Scheduling/iTip: TypeError in IMipService::generateOccurringString() — DateTime::diff(null) when recurrence set is exhausted, invitation mails never sent

Open Beginner friendly
#62,717 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

33-feedback
Dominant language
PHP
Stars
36.9k
Forks
5.2k
Avg merge
2d 3h
Merged PRs (30d)
713

Description

Bug description

IMipService::generateOccurringString() crashes with a TypeError while building an iTip invitation email for a recurring event whose recurrence set is already exhausted (last occurrence lies in the past).

The first call to $er->recurrenceDate() is passed straight into DateTime::diff() without a null check:

https://github.com/nextcloud/server/blob/stable33/apps/dav/lib/CalDAV/Schedule/IMipService.php#L658-L662

// forward to current date
$er->recurrenceAdvanceTo($this->timeFactory->getDateTime());
// calculate time difference from now to start of next event occurrence and minimize it
$occurrenceIn = $this->minimizeInterval($this->timeFactory->getDateTime()->diff($er->recurrenceDate()));

Once recurrenceAdvanceTo(now) has advanced past the final occurrence, EventReader::recurrenceDate() returns null, so the call throws:

TypeError: DateTime::diff(): Argument #1 ($targetObject) must be of type DateTimeInterface, null given

Notably, the branches a few lines further down in the same method do guard this (if ($er->recurrenceDate() !== null)) — only this first call is missing the check.

Consequence: the scheduling email is never built, so attendees silently receive no iTip invitation (no mail with accept/decline buttons). From the organizer's point of view everything looks fine, which makes this hard to notice and debug.

The code is identical in stable33, stable34 and master (checked 2026-07-31).

Possibly related: #52556 (null-handling regression in IMipService reported for 31.0.4).

Suggested fix: guard the first recurrenceDate() call like the ones below it and fall back to a sensible string (or skip the "occurring in" fragment) when the recurrence set is exhausted.

Steps to reproduce
  1. Create a recurring event whose recurrence set ends in the past (e.g. weekly with an UNTIL before today, or an exhausted COUNT)
  2. Invite an attendee (external email address) so an iTip invitation mail is generated
  3. Mail generation crashes with the TypeError above; the attendee never receives the invitation

We hit this repeatedly in production with a user-created event series on 33.0.3 through 33.0.5. Deleting the affected event from the calendar trash bin stops the crashes (the event URI had the -deleted.ics suffix in oc_calendarobjects).

Expected behavior

The invitation email is generated even when the recurrence set is exhausted.

Installation method

Official community Docker image (nextcloud:33-apache)

Nextcloud Server version

33.0.5 — but the affected code is unchanged in stable34 and master

Web server / Database

Apache (bundled in image), PostgreSQL 16

Is this bug present after an update or on a fresh install?

Observed at least since 33.0.3, unchanged through 33.0.5.

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/Schedule/IMipService.php around lines 658-662 and trace how recurrenceAdvanceTo() affects recurrenceDate() when the set is exhausted. Reproduce with a recurring event whose UNTIL or COUNT is in the past, then verify that iTip invitation mail generation completes without the TypeError and the attendee receives the invitation.

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
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.