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 = configView on GitHub (pinned to 88bb9c8533)
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.
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
- 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.
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
- matrix: configured channels.matrix.user-id ({configured}) do
- matrix: whoami response did not include device_id; configure
- matrix: whoami request failed with HTTP {status}: {body}
- matrix: {reason} Cannot auto-recover because channels.matrix
- matrix login requires either access_token or user_id+passwor
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/dc1b012e20f03cb5.
Report an issue: GitHub.