Management API panics (unreachable!) when changing an existing account's @type (User ↔ Group)

Issue Description

Changing the Account type of an existing principal from User to Group (or vice versa) — via the web-admin, the management JMAP API, or stalwart-cli — panics a worker thread and the connection is dropped without an HTTP response. The server process itself keeps running (only the request task dies).

Expected Behavior

A client request must never panic a worker thread or drop the connection — validate_account should return a result instead of hitting unreachable!(). Concretely, one of:

If account types are intentionally immutable (which the current match arms imply): the API should reject the update with a clean JMAP SetError — e.g. notUpdated with type invalidProperties on @type and a message like “the account type cannot be changed after creation”. The web-admin should then display that message instead of NetworkError when attempting to fetch resource, and ideally disable/hide the Account type selector when editing an existing account (it’s only meaningful at creation).
If converting an account’s type is meant to be supported: implement the missing match arms in validate_account so a User → Group (and Group → User) transition is handled — retaining the existing mailbox/data and adjusting the type-specific fields (credentials, roles, members) accordingly.
In both cases the _ => unreachable!() arm should be replaced with a proper, non-panicking error path, so malformed or unsupported updates are reported to the client rather than terminating the connection.

Actual Behavior

Panic
thread ‘tokio-rt-worker’ panicked at crates/jmap/src/registry/mapping/principal.rs:248:14:
internal error: entered unreachable code

Reproduction Steps

Web-admin: pick a User account (empty mailbox is fine) → Edit → Account type → Group account → Save → NetworkError when attempting to fetch resource.
Equivalent management API call:
{
“using”: [“urn:ietf:params:jmap:core”, “urn:stalwart:jmap”],
“methodCalls”: [
[“Account/set”, { “accountId”: “”, “update”: { “”: { “@type”: “Group” } } }, “c0”]
]
}
→ worker panics (above), connection dropped, no methodResponses.
Also via stalwart-cli … account update --field @type=Group.

Relevant Log Output

docker logs stalwart --since 2m 2>&1

thread ‘tokio-rt-worker’ (7) panicked at crates/jmap/src/registry/mapping/principal.rs:248:14:
internal error: entered unreachable code

thread ‘tokio-rt-worker’ (7) panicked at crates/jmap/src/registry/mapping/principal.rs:248:14:
internal error: entered unreachable code

thread ‘tokio-rt-worker’ (7) panicked at crates/jmap/src/registry/mapping/principal.rs:248:14:
internal error: entered unreachable code

thread ‘tokio-rt-worker’ (7) panicked at crates/jmap/src/registry/mapping/principal.rs:248:14:

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

Good bug report. Let me look at the relevant source code to understand and confirm what’s happening.

This confirms the bug exactly as reported. The match in validate_account only handles four arms:

  1. (Account::User(_), AccountUpdate::Update(Account::User(_))) - User updating a User
  2. (Account::Group(_), AccountUpdate::Update(Account::Group(_))) - Group updating a Group
  3. (Account::User(_), AccountUpdate::Create(_)) - Creating a User
  4. (Account::Group(_), AccountUpdate::Create(_)) - Creating a Group

Any cross-type update (e.g. User → Group or Group → User) falls through to _ => unreachable!(), which panics the worker thread. This is a confirmed bug in the source at crates/jmap/src/registry/mapping/principal.rs:248.

This is a confirmed server-side bug. When a Account/set update changes @type across principal types (User to Group or vice versa), the validate_account function hits a _ => unreachable!() arm with no error handling, causing the worker thread to panic and the connection to be dropped with no response.

The fix needs to happen in crates/jmap/src/registry/mapping/principal.rs - the _ => unreachable!() arm (line 248) must be replaced with a proper return Ok(Err(...)) that surfaces a SetError to the client (e.g. invalidProperties on @type), rather than panicking. Until then, the workaround is to never change @type on an existing account - delete and recreate it instead.

The web-admin UI also contributes to this: the Account type selector should ideally be disabled/hidden when editing an existing account (since it has no valid update path), to prevent users from hitting this panic.

A human maintainer will need to action the fix in the server source.

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