zeroclaw-labs/zeroclaw · error · anyhow::Error

matrix: configured channels.matrix.device-id ({configured})

Error message

matrix: configured channels.matrix.device-id ({configured}) does not match Matrix whoami device_id ({actual})

What it means

Part of access-token identity validation: after whoami, if both the configured channels.matrix.device-id and the whoami device_id are present and differ, login aborts. The token would sign events as a different device than the operator pinned - breaking device-based session management and E2EE trust - so the mismatch is fatal.

Source

Thrown at crates/zeroclaw-channels/src/matrix.rs:1642

                device_id: Some(device_id.clone()),
            });
        }

        let whoami = fetch_access_token_whoami(config).await?;

        if let Some(ref configured) = configured_user_id
            && configured != &whoami.user_id
        {
            bail!(
                "matrix: configured channels.matrix.user-id ({configured}) does not match Matrix whoami user_id ({})",
                whoami.user_id
            );
        }

        if let (Some(configured), Some(actual)) = (&configured_device_id, &whoami.device_id)
            && configured != actual
        {
            bail!(
                "matrix: configured channels.matrix.device-id ({configured}) does not match Matrix whoami device_id ({actual})"
            );
        }

        if configured_device_id.is_none() && whoami.device_id.is_none() {
            bail!(
                "matrix: whoami response did not include device_id; configure channels.matrix.device-id for access-token login"
            );
        }

        Ok(AccessTokenIdentity {
            user_id: configured_user_id.unwrap_or(whoami.user_id),
            device_id: configured_device_id.or(whoami.device_id),
        })
    }

    async fn fetch_access_token_whoami(config: &MatrixConfig) -> Result<WhoamiResponse> {
        let access_token = config

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Query whoami with the token and update channels.matrix.device-id to the returned device_id.
  2. Or remove the configured device-id so login adopts the token's device.
  3. Or re-create the token by logging in on the intended device and keep the token/device-id pair consistent.
  4. Store token and device-id together in one secret so they rotate as a unit.

Example fix

# before
[channels.matrix]
access-token = "syt_new..."
device-id = "OLDDEVICE123"

# after (whoami reports ABCD123EFG)
[channels.matrix]
access-token = "syt_new..."
device-id = "ABCD123EFG"
Defensive patterns

Strategy: validation

Validate before calling

async fn token_device_matches(cfg: &MatrixConfig) -> anyhow::Result<bool> {
    let url = format!(
        "{}/_matrix/client/v3/account/whoami",
        cfg.homeserver.trim_end_matches('/')
    );
    let who: serde_json::Value = reqwest::Client::new()
        .get(url)
        .bearer_auth(cfg.access_token.as_deref().unwrap_or_default())
        .send().await?
        .error_for_status()?
        .json().await?;
    Ok(who["device_id"].as_str() == cfg.device_id.as_deref())
}

Prevention

When it happens

Trigger: Access-token login where the token's device (whoami device_id) differs from channels.matrix.device-id - e.g. the token was re-issued after a logout, minting a new device id, while config still names the old device.

Common situations: Logging the bot out and back in (every login mints a new device id); copying device-id from another client's session; tokens minted via a different client than the one whose device id was captured in config.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/dc1b012e20f03cb5. Report an issue: GitHub.