Summary
CalDAVService.respond_to_event (the interactive RSVP path) writes the RSVP'd
copy of an event via _put_event, which derives the CalDAV resource filename
from the event UID (<uid>.ics). CalDAV resource names are not required to equal
the UID — whichever client created the event chose the filename.
When the mailbox's copy of the event was created under a different resource name
(e.g. added via the Calendars web UI, then RSVP'd from mail), the PUT to
<uid>.ics targets a different resource than the existing one, so it either:
- hits RFC 4791's UID-uniqueness rule and fails with 409 (the RSVP silently
never lands), or
- on a lax server, creates a duplicate event with the same UID.
Where
src/backend/core/services/calendar/service.py — respond_to_event →
_put_event, which builds event_url = calendar_url.rstrip("/") + "/" + quote(uid, safe="") + ".ics".
Suggested fix
Same approach used for the inbound apply path: locate the event via a
calendar-query REPORT that returns d:href + d:getetag, then PUT back to the
event's real resource href with If-Match on the etag. Fall back to <uid>.ics
only when the event doesn't yet exist on the calendar (first RSVP).
Notes
Pre-existing; not a regression. Surfaced while reviewing the inbound iTIP
METHOD:REPLY work, which fixed the same class of bug on the apply path.
Summary
CalDAVService.respond_to_event(the interactive RSVP path) writes the RSVP'dcopy of an event via
_put_event, which derives the CalDAV resource filenamefrom the event UID (
<uid>.ics). CalDAV resource names are not required to equalthe UID — whichever client created the event chose the filename.
When the mailbox's copy of the event was created under a different resource name
(e.g. added via the Calendars web UI, then RSVP'd from mail), the PUT to
<uid>.icstargets a different resource than the existing one, so it either:never lands), or
Where
src/backend/core/services/calendar/service.py—respond_to_event→_put_event, which buildsevent_url = calendar_url.rstrip("/") + "/" + quote(uid, safe="") + ".ics".Suggested fix
Same approach used for the inbound apply path: locate the event via a
calendar-query
REPORTthat returnsd:href+d:getetag, then PUT back to theevent's real resource href with
If-Matchon the etag. Fall back to<uid>.icsonly when the event doesn't yet exist on the calendar (first RSVP).
Notes
Pre-existing; not a regression. Surfaced while reviewing the inbound iTIP
METHOD:REPLYwork, which fixed the same class of bug on the apply path.