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

  1. 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.
  2. 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.
  3. For 5xx, retry after a delay - the homeserver is temporarily unavailable or upgrading.
  4. 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

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


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