Cloudron makes it easy to run web apps like WordPress, Nextcloud, GitLab on your server. Find out more or install now.


Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Bookmarks
  • Search
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo

Cloudron Forum

Offical apps | Community apps | Demo | Docs | Install
  1. Cloudron Forum
  2. Calendar
  3. Recurring event exceptions (RECURRENCE-ID / EXDATE) are silently dropped on CalDAV PUT

Recurring event exceptions (RECURRENCE-ID / EXDATE) are silently dropped on CalDAV PUT

Scheduled Pinned Locked Moved Solved Calendar
3 Posts 2 Posters 30 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • KubernetesK
    KubernetesK
    Kubernetes
    App Dev Super Fan
    wrote last edited by
    #1

    Calendar: Recurring event exceptions (RECURRENCE-ID / EXDATE) are silently dropped on CalDAV PUT

    Summary

    When a single occurrence of a recurring event is moved or deleted from a CalDAV client (Apple Calendar on macOS and iOS), the Calendar app accepts the request with a success response but stores only the master event. The exception is lost without any error. Other clients then fetch the event again and fall back to the unmodified series, which also wipes the exception on devices that had shown it before. The published ICS feed never contains any exceptions.

    This is silent data loss: users believe their change was saved, but it only exists locally on the editing device until the next resync.

    Environment

    Cloudron app Calendar (io.cloudron.calendar) 1.14.2
    Docker image cloudron/io.cloudron.calendar:202611041546350000
    Release commit be2a8d35455babde3cc0165113323b5bd1943c78
    Clients Apple Calendar on macOS and iOS (CalDAV account)
    Calendar Shared calendar, two users with write access

    The behaviour was already present in 1.13.0.

    Steps to reproduce

    1. In Apple Calendar (CalDAV account on the Calendar app), create a weekly recurring event, e.g. Wednesdays 08:30–17:30.
    2. Move a single occurrence to another day and choose "Only this event".
    3. Check the event on a second device with the same account or a shared user, or open the calendar's published ICS link.
    4. Optionally, edit the same series on the second device, then look at the first device again.

    Expected behaviour

    • The moved occurrence is stored on the server as an override (a VEVENT with RECURRENCE-ID), and a deleted occurrence as EXDATE on the master.
    • All clients and the ICS feed show the moved or deleted occurrence.
    • If the server cannot store exceptions, it should reject the PUT instead of reporting success.

    Actual behaviour

    • The editing device shows the moved occurrence, but only from its local copy.
    • All other devices and the ICS feed show the unmodified series.
    • As soon as the event is saved again from another device, the server issues a new ETag. The first device refetches the event and its exception disappears as well.
    • In our shared calendar the ICS feed contains 53 recurring series and zero RECURRENCE-ID, EXDATE, RDATE or STATUS:CANCELLED entries, although several occurrences were moved on the clients.

    Root cause (from the source in the image)

    1. Only the first VEVENT is parsed. src/ical.js, parseIcsToEvent() (around lines 236–287) is documented as "first VEVENT only" and stops at the first END:VEVENT. Apple Calendar sends the master VEVENT plus one VEVENT per modified occurrence (same UID, with RECURRENCE-ID) in a single resource (RFC 4791 §4.1). Every VEVENT after the first one is ignored.

    2. The PUT overwrites the stored event and reports success. src/events.js, saveEventFromIcs() (around lines 556–597) updates the existing row with the parsed first VEVENT and generates a new ETag. src/routes/caldav.js, handlePut() (around lines 359–428) answers 204 No Content with that ETag. The client therefore considers the change saved.

    3. No storage for exceptions. The events table (src/database.js, around lines 90–108) has only recurrence_rule. There is no column or table for overrides or excluded dates.

    4. EXDATE / RECURRENCE-ID / RDATE are not handled anywhere. A search over src/ (excluding tests) finds no occurrence of EXDATE, RECURRENCE-ID or RDATE. Deleting a single occurrence (which Apple sends as EXDATE on the master) is lost in the same way.

    Possible follow-up issue, not observed in practice: because only the first VEVENT is read, a client that puts an override VEVENT before the master would overwrite the series itself with the single occurrence. Apple Calendar happens to send the master first.

    Impact

    • Moved or deleted occurrences of recurring events are lost for every other user and device, and eventually for the editing device too.
    • In shared calendars, one user's edit silently reverts the other users' changes.
    • Anything consuming the ICS feed (dashboards, subscriptions) shows wrong dates.

    Suggested fix

    • Parse all VEVENTs of a resource and store overrides (RECURRENCE-ID) and EXDATE (ideally also RDATE) together with the master event.
    • Apply them during recurrence expansion and include them in CalDAV GET/REPORT responses and in the ICS export.
    • Until that is implemented: reject a PUT that contains RECURRENCE-ID overrides or EXDATE (e.g. 403 with a CALDAV:valid-calendar-object-resource precondition, or 415) instead of returning 204. Clients would then show a sync error instead of silently losing data.

    Workaround

    Do not move or delete single occurrences of a series. End the series and create a new one, or use individual events instead.


    Disclosure: I found this problem and made the observations described above myself, on my own devices and with our shared calendar. The source code analysis and the wording of this report were done with the help of an AI assistant.

    1 Reply Last reply
    1
    • nebulonN
      nebulonN
      nebulon
      Staff
      wrote last edited by
      #2

      Thanks for your report. Recurring event exceptions should be now supported by the just released new calendar version.

      1 Reply Last reply
      1
      • KubernetesK
        KubernetesK
        Kubernetes
        App Dev Super Fan
        wrote last edited by
        #3

        Great news, thanks @nebulon !

        1 Reply Last reply
        0
        • nebulonN nebulon marked this topic as a question
        • nebulonN nebulon has marked this topic as solved

        Hello! It looks like you're interested in this conversation, but you don't have an account yet.

        Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

        With your input, this post could be even better 💗

        Register Login
        Reply
        • Reply as topic
        Log in to reply
        • Oldest to Newest
        • Newest to Oldest
        • Most Votes


        • Login

        • Don't have an account? Register

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Bookmarks
        • Search