larksuite/cli · error
fetch bot info: HTTP %d
Error message
fetch bot info: HTTP %d
What it means
The bot info endpoint returned an HTTP status >= 400, so the response is not usable. The library reports the status code without parsing a body, because at this layer the status alone indicates the API rejected the request (auth, permissions, or gateway error).
Source
Thrown at shortcuts/common/runner.go:171
return nil, fmt.Errorf("BotInfo not available (runtime context not fully initialized)")
}
return ctx.botInfoFunc()
}
// fetchBotInfo calls /bot/v3/info using bot identity and parses the response.
func (ctx *RuntimeContext) fetchBotInfo() (*BotInfo, error) {
if !ctx.Config.CanBot() {
return nil, fmt.Errorf("fetch bot info: bot identity is not available in current credential context")
}
resp, err := ctx.DoAPIAsBot(&larkcore.ApiReq{
HttpMethod: http.MethodGet,
ApiPath: "/open-apis/bot/v3/info",
})
if err != nil {
return nil, fmt.Errorf("fetch bot info: %w", err)
}
if resp.StatusCode >= 400 {
return nil, fmt.Errorf("fetch bot info: HTTP %d", resp.StatusCode)
}
// /open-apis/bot/v3/info returns `{code, msg, bot: {...}}` — the bot
// payload is under "bot", not "data" as the newer Lark API convention.
var envelope struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
OpenID string `json:"open_id"`
AppName string `json:"app_name"`
} `json:"bot"`
}
if err := json.Unmarshal(resp.RawBody, &envelope); err != nil {
return nil, fmt.Errorf("fetch bot info: unmarshal: %w", err)
}
if envelope.Code != 0 {
return nil, fmt.Errorf("fetch bot info: [%d] %s", envelope.Code, envelope.Msg)
}
if envelope.Data.OpenID == "" {View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Check the HTTP status in the message: 401/403 → fix bot credentials/scopes; 404 → verify API base URL; 5xx → retry later
- Grant the app the scopes required for /open-apis/bot/v3/info and enable bot capability
- Re-run after refreshing credentials; if persistent, capture the raw response with debug logging to see the error body
Defensive patterns
Strategy: try-catch
Try / catch
info, err := ctx.BotInfo()
if err != nil {
var httpErr struct{ Status int }
if m := regexp.MustCompile(`HTTP (\d+)`).FindStringSubmatch(err.Error()); m != nil {
switch m[1] {
case "401", "403": /* fix scopes/credentials */
case "404": /* check base URL */
default: /* retry later for 5xx */
}
}
return err
} Prevention
- Grant the app all scopes required by /open-apis/bot/v3/info
- Keep the API base URL/gateway configuration pointing at the correct environment
- Monitor for 5xx and add bounded retry with backoff for transient server errors
When it happens
Trigger: DoAPIAsBot succeeded at transport level but /bot/v3/info replied 4xx/5xx — e.g. 401/403 from missing bot scopes or invalid bot token, 404 from wrong API base/gateway, 5xx from server-side issues.
Common situations: App missing the bot capability or required scopes for /bot/v3/info; stale token after credential rotation; misconfigured gateway/base-URL override pointing at the wrong environment.
Related errors
- fetch bot info: %w
- Device authorization failed: read body: %v
- failed to read response body in security transport: %w
- [%d] %s
- user_info API error: [%d] %s
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/1c9fe9920a5556e0.
Report an issue: GitHub.