Admin account cannot SEARCH (IMAP SEARCH / JMAP Email/query): internal account id u32::MAX collides with "no account id" sentinel

Issue Description

The internal admin/recovery account cannot perform any SEARCH operations on Stalwart v0.16.x (verified on v0.16.16 and v0.16.19; also present in current main). Regular user accounts are unaffected.

Root Cause

The internal admin account’s JMAP id d333333 decodes to u64 4294967295, so Id::document_id() returns u32::MAX. The search dispatch code uses u32::MAX as a sentinel for “no account id was specified in the query” in two places:

  • crates/store/src/dispatch/search.rs (~lines 31-55)
  • crates/store/src/search/query.rs (~lines 36-56)

A search issued for the admin account is therefore indistinguishable from a search with no account filter, and the dispatcher rejects it with NO [CONTACTADMIN] Unexpected error.

Proposed Fix

Replace the u32::MAX sentinel with Option<u32> so that Some(id) (including u32::MAX for the admin account) can be distinguished from None (no account filter). ~12-line change across the two files, no API or behavior change for regular accounts. Reference implementation (compiles + unit tests) available in our fork: github.com/tobias-weiss-ai-xr/mail-server, commit 4238ece1.

Workaround

Use a regular user account for SEARCH operations; the bug only affects the internal admin account.

Expected Behavior

The internal admin account should be able to search its mail like any other account: IMAP SEARCH ALL / UID SEARCH ALL return matching messages, and JMAP Email/query returns ids.

Actual Behavior

IMAP: a SEARCH ALL returns a NO [CONTACTADMIN] Unexpected error (same for UID SEARCH). JMAP Email/query returns a server error. Only the internal admin account is affected; regular user accounts search normally.

Reproduction Steps

  1. Run Stalwart v0.16.16 or v0.16.19 (official Docker image; also reproduced from source).
  2. Connect via IMAPS (port 993) and log in as the internal admin account.
  3. SELECT INBOX.
  4. Issue SEARCH ALL (or UID SEARCH ALL).
  5. Observe: NO [CONTACTADMIN] Unexpected error.
  6. Alternative: authenticate the admin account against JMAP and issue an Email/query call - the server returns an error instead of ids.
  7. Repeat the same steps with a regular user account - search works fine.

Relevant Log Output

IMAP session as internal admin account:

* OK Stalwart IMAP4rev1 ready
a1 LOGIN admin <password>
a1 OK Completed
a2 SELECT INBOX
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
* 5 EXISTS
a2 OK Completed
a3 SEARCH ALL
a3 NO [CONTACTADMIN] Unexpected error

Same session with a regular user account:

b1 LOGIN testuser <password>
b1 OK Completed
b2 SELECT INBOX
b2 OK Completed
b3 SEARCH ALL
* SEARCH 1 2 3 4 5
b3 OK Completed

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

PostgreSQL

Blob Storage

PostgreSQL

Search Engine

Internal

Directory Backend

Internal

Additional Context

  • Found via an automated integration test suite against our evaluation cluster (k3s, 3 Stalwart replicas, PostgreSQL data/blob backend).
  • Reproduced with raw IMAP (Python imaplib) and JMAP HTTP calls; no client software involved.
  • Verified on v0.16.16 (self-built) and v0.16.19 (official Docker Hub image); the sentinel is also present in current main.
  • Reference implementation of the Option fix (compiles, unit tests included) in our fork: github.com/tobias-weiss-ai-xr/mail-server, commit 4238ece1.

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

Confirmed in the current source: crates/store/src/dispatch/search.rs initializes account_id to u32::MAX as the “not set” sentinel, and if no explicit AccountId::Equal filter overwrites it, the query is rejected with StoreEvent::UnexpectedError (which the IMAP layer reports as NO [CONTACTADMIN] Unexpected error):

let mut account_id = u32::MAX;
...
SearchFilter::Operator {
    field: SearchField::AccountId,
    op: SearchOperator::Equal,
    value: SearchValue::Uint(id),
} => {
    account_id = *id as u32;
}
...
if account_id == u32::MAX {
    return Err(trc::StoreEvent::UnexpectedError
        .reason("Account ID filter is required for account queries")
        .caused_by(trc::location!()));
}

Since the internal admin/recovery account’s document id happens to also be u32::MAX, this collides exactly as you described, making the “no filter set” sentinel indistinguishable from “filter set to the admin account’s real id.” This matches your root-cause analysis precisely; your proposed Option<u32> fix would resolve the ambiguity without touching behavior for any other account. This is a genuine bug in the current codebase, not a documentation gap, so it will need to be picked up by staff/engineering; a human will follow up on this thread.

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

The recovery admin account is just for recovery and initial setup, you should use a regular admin account after that. In addition to that, it is never a good idea to configure an email client with an administrator account.