CalDAV REPORT calendar-query returns invalid HTTP 404 for existing calendar with no events matching

Issue Description

I’m trying to find VEVENT items in my calendar in a specific time range using a REPORT HTTP call with a calendar-query.

My CalDAV HTTP request looks like this:

<?xml version="1.0" encoding="utf-8"?>
<c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:ca="http://apple.com/ns/ical/" xmlns:d="DAV:">
  <d:prop>
    <d:getetag/>
    <c:calendar-data>
      <c:expand start="20260217T000000Z" end="20260217T235959Z"/>
    </c:calendar-data>
  </d:prop>
  <c:filter>
    <c:comp-filter name="VCALENDAR">
      <c:comp-filter name="VEVENT">
        <c:time-range start="20260217T000000Z" end="20260217T235959Z"/>
      </c:comp-filter>
    </c:comp-filter>
  </c:filter>
</c:calendar-query>

In my queried calendar, I do not have any events for the queried date of 2026-02-17.

Expected Behavior

The response should be a an empty multistatus according to RFC 4791 section 7.8:

The response body for a successful request MUST be a DAV:
multistatus XML element (i.e., the response uses the same format
as the response for PROPFIND). In the case where there are no
response elements, the returned DAV:multistatus XML element is
empty.

For instance, Google Calendar CalDAV API responds

<?xml version="1.0" encoding="UTF-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:caldav="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:ical="http://apple.com/ns/ical/"/>

for the same query.

Actual Behavior

The response is a 207 Multi-Status with a response element reporting an 404 Not Found:

<?xml version="1.0" encoding="UTF-8"?>
<D:multistatus xmlns:D="DAV:">
    <D:response>
        <D:href>/dav/cal/my-ser%40my-domain.tld/default</D:href>
        <D:status>HTTP/1.1 404 Not Found</D:status>
        <D:responsedescription>No resources found</D:responsedescription>
    </D:response>
</D:multistatus>

For my consumer use case, this makes it hard to interpret the state of “this property does not exist” and “during this time range, there are no events”.

(I tested extending the query time-range to a date where events match to ensure that the query itself is not malformed).

Reproduction Steps

  1. Setup clean Stalwart
  2. Create a user with a calendar and an API key
  3. Query the calendar using the REPORT body provided

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

Let me look at the CalDAV REPORT/calendar-query handling in the server source code.

This is a confirmed bug in Stalwart’s REPORT calendar-query implementation. The relevant code in crates/dav/src/common/propfind.rs (around line 1128-1131) shows that when a calendar-query REPORT returns zero matching results and it is not a PROPFIND, the server calls MultiStatus::not_found(query.uri) instead of returning an empty <D:multistatus/>.

Specifically, the logic is:

if !response.response.0.is_empty() || !query.sync_type.is_none() {
    Ok(HttpResponse::new(StatusCode::MULTI_STATUS).with_xml_body(response.to_string()))
} else if !is_propfind {
    Ok(HttpResponse::new(StatusCode::MULTI_STATUS)
        .with_xml_body(MultiStatus::not_found(query.uri).to_string()))  // <-- wraps 404 inside 207
} else {
    Ok(HttpResponse::new(StatusCode::NOT_FOUND))
}

When the calendar exists but no events match the filter, response.response.0 is empty, and the !is_propfind branch fires, producing a 207 Multi-Status body containing a 404 Not Found response element instead of an empty <D:multistatus/> as required by RFC 4791 section 7.8.

The correct behavior per the RFC is to return a 207 Multi-Status with an empty <D:multistatus/> element when the calendar exists but no items match the filter. The current code conflates “calendar not found” with “calendar found but no matching events.”

This is a bug that needs to be fixed in the server’s propfind.rs handler – the empty-result path for REPORT requests on an existing collection should produce an empty multistatus, not a not_found multistatus.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

This has been fixed in v0.16.12 which will be released this week.