{"record":{"id":"dc1b012e20f03cb5","repo":"zeroclaw-labs/zeroclaw","slug":"matrix-configured-channels-matrix-device-id-con","errorCode":null,"errorMessage":"matrix: configured channels.matrix.device-id ({configured}) does not match Matrix whoami device_id ({actual})","messagePattern":"matrix: configured channels\\.matrix\\.device-id \\((.+?)\\) does not match Matrix whoami device_id \\((.+?)\\)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/matrix.rs","lineNumber":1642,"sourceCode":"                device_id: Some(device_id.clone()),\n            });\n        }\n\n        let whoami = fetch_access_token_whoami(config).await?;\n\n        if let Some(ref configured) = configured_user_id\n            && configured != &whoami.user_id\n        {\n            bail!(\n                \"matrix: configured channels.matrix.user-id ({configured}) does not match Matrix whoami user_id ({})\",\n                whoami.user_id\n            );\n        }\n\n        if let (Some(configured), Some(actual)) = (&configured_device_id, &whoami.device_id)\n            && configured != actual\n        {\n            bail!(\n                \"matrix: configured channels.matrix.device-id ({configured}) does not match Matrix whoami device_id ({actual})\"\n            );\n        }\n\n        if configured_device_id.is_none() && whoami.device_id.is_none() {\n            bail!(\n                \"matrix: whoami response did not include device_id; configure channels.matrix.device-id for access-token login\"\n            );\n        }\n\n        Ok(AccessTokenIdentity {\n            user_id: configured_user_id.unwrap_or(whoami.user_id),\n            device_id: configured_device_id.or(whoami.device_id),\n        })\n    }\n\n    async fn fetch_access_token_whoami(config: &MatrixConfig) -> Result<WhoamiResponse> {\n        let access_token = config","sourceCodeStart":1624,"sourceCodeEnd":1660,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/matrix.rs#L1624-L1660","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Query whoami with the token and update channels.matrix.device-id to the returned device_id.","Or remove the configured device-id so login adopts the token's device.","Or re-create the token by logging in on the intended device and keep the token/device-id pair consistent.","Store token and device-id together in one secret so they rotate as a unit."],"exampleFix":"# before\n[channels.matrix]\naccess-token = \"syt_new...\"\ndevice-id = \"OLDDEVICE123\"\n\n# after (whoami reports ABCD123EFG)\n[channels.matrix]\naccess-token = \"syt_new...\"\ndevice-id = \"ABCD123EFG\"","handlingStrategy":"validation","validationCode":"async fn token_device_matches(cfg: &MatrixConfig) -> anyhow::Result<bool> {\n    let url = format!(\n        \"{}/_matrix/client/v3/account/whoami\",\n        cfg.homeserver.trim_end_matches('/')\n    );\n    let who: serde_json::Value = reqwest::Client::new()\n        .get(url)\n        .bearer_auth(cfg.access_token.as_deref().unwrap_or_default())\n        .send().await?\n        .error_for_status()?\n        .json().await?;\n    Ok(who[\"device_id\"].as_str() == cfg.device_id.as_deref())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Rotate token and device-id as a unit: store them together and refresh both after any logout.","Re-run the whoami preflight whenever a token is replaced.","Record which client/login minted each token so device provenance is known."],"tags":["matrix","auth","access-token","whoami","device-id","config"],"backgroundTag":"auth-identity-mismatch","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}