Server compatibility#
Each table lists what the tested servers did where sync depends on it, and what the adapter does about it. The CalDAV adapter was checked against Radicale 3.8.3, Xandikos 0.4.8, Cyrus 3.13.7, Stalwart 0.16.21 and Baïkal 0.10.1, and the JMAP adapter against Cyrus 3.13.7 and Stalwart 0.16.21, between 2026-10-10 and 2026-10-12. A later release may behave differently. The probes and logs behind every row are on the evidence branch, with the steps to reproduce them. Adapters explains each rule, and the Glossary defines the sync terms in the Adapter column.
CalDAV#
Behavior |
Tested servers |
Adapter |
|---|---|---|
|
All: yes |
Checked before the first sync |
|
All: defined |
Read before every full listing |
Report with an empty token, after deletions (RFC 6578 Section 3.4: no removed members) |
|
Lists with |
Member created and deleted between two reports (RFC 6578 Section 3.5.2: reported as removed) |
|
A create of yours that’s never mentioned stays pending |
Member deleted and re-created at one href (RFC 6578 Section 3.5.1, RFC 6578 Section 3.2: reported once, as changed) |
|
The later entry counts, and the fetch decides |
Token the server never issued (RFC 6578 Section 3.2: |
|
Resets the scope when the error names |
Token whose history the server has discarded |
|
Resets the scope; flags Stalwart for regular full listings, which recover what it doesn’t report |
Report with |
|
Never sends |
Full listing of a calendar larger than the server’s result limit |
|
Lists with |
PUT the server stores differently (RFC 4791 Section 5.3.4: no strong ETag in the answer) |
|
Never keeps the ETag a write returns; its fingerprint ignores the rewrite |
Character set of calendar data (RFC 5545 Section 3.1.4: UTF-8 by default) |
|
Reads calendar data as UTF-8 unless the server names another charset |
Identical PUT |
All: same ETag |
A version-only change |
Create with a UID already in the calendar (RFC 4791 Section 5.3.2.1) |
|
Recognizes both elements; finding objects by UID returns every match |
|
|
The next ingest settles it |
|
|
A missing or 404 member waits for the next report |
Conditional writes behaved as RFC 9110 Section 13.1.1 and RFC 9110 Section 13.1.2 specify on every server in the table: a wrong If-Match or an If-None-Match: * on an existing resource gets 412.
JMAP#
Behavior |
Tested servers |
Adapter |
|---|---|---|
|
Both: pages correctly, |
Follows |
Event created and destroyed between two states (RFC 8620 Section 5.2: should be left out) |
|
A create of yours that’s never mentioned stays pending |
|
|
Resets the scope on either |
|
|
Resets the scope when |
State whose history the server has discarded |
Both: |
Resets the scope |
|
Both: |
Keeps the edits pending |
Properties the server adds to a stored event |
|
Stores the event as the server returns it; its fingerprint leaves those properties out or fills in their defaults |
Create without |
|
Include |
Create with a |
Both: |
Stored as a conflict record, refused for its UID |
Update or destroy of an event that’s gone |
Both: |
The next ingest settles it |
JMAP Tasks ( |
Both: not advertised, Stalwart also not on its latest image |
Events only for now |
No tested server reports a per-event version, so every event a /changes call names is fetched and compared by fingerprint.