{"record":{"id":"7cc28b4c0b641fb5","repo":"zeroclaw-labs/zeroclaw","slug":"bot-info-request-failed-status-status-body-bo","errorCode":null,"errorMessage":"bot info request failed: status={status}, body={body}","messagePattern":"bot info request failed: status=(.+?), body=(.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/lark.rs","lineNumber":1852,"sourceCode":"    }\n\n    async fn refresh_bot_open_id(&self) -> anyhow::Result<Option<String>> {\n        let token = self.get_tenant_access_token().await?;\n        let (status, body) = self.fetch_bot_open_id_with_token(&token).await?;\n\n        let body = if should_refresh_lark_tenant_token(status, &body) {\n            self.invalidate_token().await;\n            let refreshed = self.get_tenant_access_token().await?;\n            let (retry_status, retry_body) = self.fetch_bot_open_id_with_token(&refreshed).await?;\n            if !retry_status.is_success() {\n                anyhow::bail!(\n                    \"bot info request failed after token refresh: status={retry_status}, body={retry_body}\"\n                );\n            }\n            retry_body\n        } else {\n            if !status.is_success() {\n                anyhow::bail!(\"bot info request failed: status={status}, body={body}\");\n            }\n            body\n        };\n\n        let code = body.get(\"code\").and_then(|c| c.as_i64()).unwrap_or(-1);\n        if code != 0 {\n            anyhow::bail!(\"bot info failed: code={code}, body={body}\");\n        }\n\n        let bot_open_id = body\n            .pointer(\"/bot/open_id\")\n            .or_else(|| body.pointer(\"/data/bot/open_id\"))\n            .and_then(|v| v.as_str())\n            .map(str::trim)\n            .filter(|v| !v.is_empty())\n            .map(str::to_owned);\n\n        self.set_resolved_bot_open_id(bot_open_id.clone());","sourceCodeStart":1834,"sourceCodeEnd":1870,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/lark.rs#L1834-L1870","documentation":"The first GET /open-apis/bot/v3/info call with the cached tenant_access_token returned non-2xx, and the response did not indicate a stale token (not HTTP 401, not Lark code 99991663), so no refresh was attempted. The channel surfaces the status and full body. Commonly a permission/capability problem or routing issue rather than authentication expiry.","triggerScenarios":"403 when the app is not a bot or lacks permissions, 404 when api_base or the path is wrong, 429 from startup bursts hitting rate limits, or 5xx during Lark incidents.","commonSituations":"Bot capability never enabled on the custom app, scopes granted but the app version not re-published, api_base typo, or many channel instances starting simultaneously and tripping rate limits.","solutions":["Branch on status: 403 -> enable Robot capability / grant scopes and republish; 404 -> fix api_base; 429 -> add backoff; 5xx -> retry later.","Verify the app in the Lark console has bot capability and the scope needed by bot/v3/info.","If a fresh token is suspected anyway, restart the channel to force get_tenant_access_token."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match lark.fetch_bot_open_id().await {\n    Ok(id) => {}\n    Err(e) if e.to_string().contains(\"bot info request failed: status=403\") => {\n        alert(\"Lark app lacks bot capability/scopes for bot/v3/info\");\n    }\n    Err(e) if e.to_string().contains(\"status=429\") => backoff_retry().await,\n    Err(e) => return Err(e),\n}","preventionTips":["Fetch bot info once at channel startup to surface permission problems before traffic.","Back off on 429; do not hammer bot/v3/info during startup storms.","Verify app capability and published version after every console-side permission change."],"tags":["lark","bot-info","http","forbidden","rate-limit"],"backgroundTag":"http-error-response","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}