zeroclaw-labs/zeroclaw · error · anyhow::Error
matrix: whoami request failed with HTTP {status}: {body}
Error message
matrix: whoami request failed with HTTP {status}: {body} What it means
As part of access-token validation the channel GETs the homeserver's whoami endpoint and requires HTTP success. A non-success status aborts with the status code plus a body preview, which distinguishes the usual causes: 401 with M_UNKNOWN_TOKEN (revoked or expired token), 403 (forbidden), 404 (wrong homeserver base URL or proxy path), 5xx (homeserver down). A failure to even send the request surfaces earlier as the reqwest-context error 'matrix: whoami request failed'.
Source
Thrown at crates/zeroclaw-channels/src/matrix.rs:1678
let access_token = config
.access_token
.as_deref()
.context("matrix: whoami requires access_token")?;
let url = matrix_client_api_url(&config.homeserver, WHOAMI_ENDPOINT)?;
let response = reqwest::Client::builder()
.timeout(WHOAMI_TIMEOUT)
.build()
.context("matrix: build whoami HTTP client")?
.get(url)
.bearer_auth(access_token)
.send()
.await
.context("matrix: whoami request failed")?;
let status = response.status();
if !status.is_success() {
let body = read_whoami_error_body_preview(response).await;
bail!("matrix: whoami request failed with HTTP {status}: {body}");
}
let mut whoami = response
.json::<WhoamiResponse>()
.await
.context("matrix: failed to parse whoami response")?;
whoami.user_id = whoami.user_id.trim().to_string();
if whoami.user_id.is_empty() {
bail!("matrix: whoami response did not include user_id");
}
whoami.device_id = whoami
.device_id
.map(|device_id| device_id.trim().to_string())
.filter(|device_id| !device_id.is_empty());
Ok(whoami)
}
View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the body preview in the message: M_UNKNOWN_TOKEN means the token is dead - mint a new one and update channels.matrix.access-token.
- Verify channels.matrix.homeserver is the client API base (e.g. https://matrix.example.org) and that /_matrix/client/v3/account/whoami is reachable through any proxy.
- For 5xx, retry after a delay - the homeserver is temporarily unavailable or upgrading.
- If a password change invalidated the token, switch to user-id+password auth to stop token churn.
Example fix
# before: proxy serves the site root, not the client API [channels.matrix] homeserver = "https://example.org" # after [channels.matrix] homeserver = "https://matrix.example.org"
Defensive patterns
Strategy: try-catch
Validate before calling
async fn whoami_ok(cfg: &MatrixConfig) -> bool {
let url = format!(
"{}/_matrix/client/v3/account/whoami",
cfg.homeserver.trim_end_matches('/')
);
matches!(
reqwest::Client::new()
.get(url)
.bearer_auth(cfg.access_token.as_deref().unwrap_or_default())
.send()
.await,
Ok(resp) if resp.status().is_success()
)
} Try / catch
match start_matrix(config).await {
Err(err) => {
let text = format!("{err:#}");
if text.contains("whoami request failed with HTTP 401") {
// token revoked: refresh the token, then retry startup once
} else if text.contains("HTTP 5") {
// homeserver transient: back off and retry startup
} else {
return Err(err); // config problem: do not retry
}
}
ok => ok,
} Prevention
- Rotate tokens on a schedule before homeserver-side expiry or revocation.
- Point homeserver at the client API root and smoke-test whoami from the deployment host through the same proxy chain.
- Prefer password auth for bot accounts to avoid manual token lifecycle.
- Alert on 401 whoami events - they always need human action.
When it happens
Trigger: Access-token login when whoami returns non-2xx: the token was logged out via logout-all or invalidated by a password change (401), the homeserver URL is mispointed or proxied so /_matrix/client/v3/account/whoami 404s, or the homeserver is under maintenance (5xx).
Common situations: Revoked access tokens after security events; reverse proxies rewriting or dropping the Matrix client API path; homeserver pointed at a federation port instead of the client API; homeserver upgrade downtime.
Related errors
- matrix: whoami response did not include device_id; configure
- matrix: configured channels.matrix.user-id ({configured}) do
- matrix: configured channels.matrix.device-id ({configured})
- matrix: whoami response did not include user_id
- matrix: {reason} Cannot auto-recover because channels.matrix
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/a18e2866bf445f0c.
Report an issue: GitHub.