nextcloud / nextcloud/integration_davc
CalDAV sync-collection incorrectly treats property-level 404 as deleted resource
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 12
- Forks
- 2
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 16
Description
Another issue, written directly with AI about a bug with Radicale <-> Nextcloud couple,
Description
During incremental CalDAV synchronization, DAV Connector may incorrectly treat an existing calendar resource as deleted when a sync-collection response contains mixed propstat statuses.
This occurs with Radicale when the requested properties include both getetag and resourcetype.
For an existing event, Radicale can return:
<d:response>
<d:href>/admin/calendars-.../03e14d0c-db17-4408-aa0c-ce3769973ab5.ics</d:href>
<d:propstat>
<d:prop>
<d:getetag>"..."</d:getetag>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
<d:propstat>
<d:prop>
<d:resourcetype />
</d:prop>
<d:status>HTTP/1.1 404 Not Found</d:status>
</d:propstat>
</d:response>
The resource itself exists: the 200 propstat contains its ETag. The 404 applies only to the requested resourcetype property.
However, RemoteEventsService::entityDelta() currently contains:
if (isset($response[404])) {
$delta->deletions->append((string)$href);
continue;
}
Therefore, the presence of any 404 propstat causes the whole resource to be classified as deleted.
As a result, newly created events reported by sync-collection are not added to modifications, and DAV Connector never performs the subsequent calendar-multiget needed to retrieve them.
Expected behavior
A resource should not be considered deleted merely because one requested property returned 404 while other properties were successfully returned with 200.
For example, the condition could be changed from:
if (isset($response[404])) {
to:
if (!isset($response[200]) && isset($response[404])) {
This preserves the handling of actual 404 resources while allowing responses containing successful properties to continue through the normal delta processing.
Result after applying the change
After applying the above change, incremental synchronization works correctly.
Test procedure:
- Initial calendar synchronization completed successfully.
- A new event was created on the remote calendar.
- The event became available through Radicale/CalDAV.
- DAV Connector performed a
sync-collectionREPORT. - Radicale returned:
200 OKforgetetag404 Not Foundforresourcetype
- With the original code, DAV Connector classified the event as deleted and did not issue a
calendar-multigetfor it. - With the modified condition, the event was correctly included in the remote delta.
- DAV Connector fetched the event and it appeared in Nextcloud after a normal harmonization.
The successful test was performed with a newly created event without resetting the synchronization token or forcing a full synchronization.
Environment
- Nextcloud 34.0.3.2
- DAV Connector 1.1.0
- Radicale 3.2.3.1
radicale_storage_decsync- CalDAV incremental synchronization using
sync-collection
Related issues
- #168 – Empty DAV
resourcetypecauses contacts and calendar objects to be skipped - #169 – Initial CalDAV harmonization may store sync-token without importing existing events
This issue is distinct from #168: the problem here is not the value of resourcetype itself, but the fact that a property-level 404 is interpreted as if the entire DAV resource had returned 404.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at RemoteEventsService::entityDelta() and inspect how sync-collection propstat responses are grouped by status. Reproduce the Radicale response containing 200 for getetag and 404 for resourcetype, then verify that the existing resource remains in the remote delta and reaches the subsequent calendar-multiget instead of being treated as deleted.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100