zeroclaw-labs/zeroclaw · error · anyhow::Error
Failed to fetch bot info: {}
Error message
Failed to fetch bot info: {} What it means
fetch_bot_username() GETs the Bot API `getMe` endpoint (during startup/pairing to learn the bot's @username) and bails with the raw HTTP status on any non-2xx. It is usually the first authenticated call against the Bot API, so a failure almost always means the bot_token or api_base is wrong before anything else runs.
Source
Thrown at crates/zeroclaw-channels/src/telegram.rs:1533
async fn classify_edit_message_response(resp: reqwest::Response) -> EditMessageResult {
if resp.status().is_success() {
return EditMessageResult::Success;
}
let status = resp.status();
let body = resp.text().await.unwrap_or_default();
if body.contains("message is not modified") {
return EditMessageResult::NotModified;
}
EditMessageResult::Failed(status)
}
async fn fetch_bot_username(&self) -> anyhow::Result<String> {
let resp = self.http_client().get(self.api_url("getMe")).send().await?;
if !resp.status().is_success() {
anyhow::bail!("Failed to fetch bot info: {}", resp.status());
}
let data: serde_json::Value = resp.json().await?;
let result = data
.get("result")
.context("missing result in getMe response")?;
let username = result
.get("username")
.and_then(|u| u.as_str())
.context("Bot username not found in response")?;
// Cache the bot's user ID for reply-to-self detection
if let Some(id) = result.get("id").and_then(|i| i.as_i64()) {
let mut cache = self.bot_id.lock();
*cache = Some(id);
}
Ok(username.to_string())View on GitHub (pinned to 88bb9c8533)
Solutions
- Verify the token directly: `curl https://api.telegram.org/bot<TOKEN>/getMe` must return "ok":true.
- If api_base is overridden for a local Bot API server, confirm the server is up and the base URL/path is correct.
- Re-issue the token via @BotFather and update it with `zeroclaw config set channels.telegram.<alias>.bot_token <new-token>`.
- Restart the channel/process after fixing credentials.
Defensive patterns
Strategy: validation
Validate before calling
// preflight the credentials before wiring the channel
let resp = reqwest::get(format!("{api_base}/bot{token}/getMe")).await?;
anyhow::ensure!(resp.status().is_success(), "bot token rejected: {}", resp.status()); Type guard
fn is_auth_failure(err: &anyhow::Error) -> bool {
err.to_string().contains("Failed to fetch bot info: 401")
} Try / catch
if let Err(e) = channel.fetch_bot_username().await {
if is_auth_failure(&e) {
anyhow::bail!("bot_token invalid or revoked; reissue with @BotFather and update config");
}
return Err(e);
} Prevention
- Run a getMe preflight during channel startup so bad tokens fail before polling begins.
- After regenerating a token with @BotFather, update config immediately and restart.
- For self-hosted Bot API servers, health-check api_base before startup.
When it happens
Trigger: 401 Unauthorized with an invalid or revoked bot_token; 404 from a custom api_base pointing at a local telegram-bot-api-server that is not running or has the wrong path; an intermediate proxy returning an error page status.
Common situations: Token regenerated with @BotFather after the old one was revoked; copy-paste typo in the token; api_base override for a self-hosted Bot API server misconfigured; captive portals or corporate proxies intercepting the request.
Related errors
- gateway registration failed ({status}): {err}
- git channel has no repositories to poll; set `repos` or gran
- matrix: {reason} Cannot auto-recover because channels.matrix
- matrix login requires either access_token or user_id+passwor
- matrix: configured channels.matrix.user-id ({configured}) do
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/666785f7a2bc963d.
Report an issue: GitHub.