larksuite/cli · error
fetch bot info: unmarshal
Error message
fetch bot info: unmarshal: %w
What it means
The HTTP response body of /bot/v3/info could not be decoded into the expected {code, msg, bot:{open_id, app_name}} envelope. This means the gateway returned an unexpected payload (HTML error page, different schema, truncated body). Note the bot payload lives under "bot", not "data", per this API's older convention.
Solutions
- Log/inspect resp.RawBody to see the actual payload and confirm it is the expected JSON envelope
- If a proxy/SSO layer intercepts requests, bypass or authenticate it so the real Lark API responds
- Update the CLI if the endpoint schema changed; verify against the current /bot/v3/info contract
Defensive patterns
Strategy: validation
Validate before calling
// Confirm the gateway returns JSON before parsing bot info:
resp, err := http.Get(baseURL + "/open-apis/bot/v3/info")
if err == nil && !strings.HasPrefix(strings.TrimSpace(http.DetectContentType(resp.Body[:512]), "application/json") { /* proxy/HTML interstitial */ } Try / catch
info, err := ctx.BotInfo()
if err != nil && strings.Contains(err.Error(), "unmarshal:") {
// unexpected payload: check for proxy/auth HTML, schema change
return fmt.Errorf("bot info endpoint returned non-JSON payload: %w", err)
} Prevention
- Bypass proxies/captive portals that inject HTML into API responses
- Pin the CLI to a gateway environment matching the expected /bot/v3/info schema
- Update the CLI when Lark changes the response envelope
When it happens
Trigger: json.Unmarshal(resp.RawBody, &envelope) fails — non-JSON body (proxy/auth HTML interstitial), a schema change in the endpoint response, or a corrupted/truncated response.
Common situations: Corporate proxy or captive portal returning HTML; API version/gateway changes altering the payload; hitting a mock or wrong environment returning unexpected JSON.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- array default for requires exactly items, got
- ErrMalformedConfig
- expected object, got
- expected string key, got
- fetch bot info: open_id is empty
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/881bf2d47ab5528d.
Report an issue: GitHub.
Appendix: source
Thrown at shortcuts/common/runner.go:184
})
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 == "" {
return nil, fmt.Errorf("fetch bot info: open_id is empty")
}
return &BotInfo{OpenID: envelope.Data.OpenID, AppName: envelope.Data.AppName}, nil
}
// Ctx returns the context.Context propagated from cmd.Context().
func (ctx *RuntimeContext) Ctx() context.Context { return ctx.ctx }
// getAPIClient returns the cached APIClient, creating it on first use.
// Thread-safe via sync.OnceValues (initialized in newRuntimeContext).
// Falls back to direct construction for test contexts that bypass newRuntimeContext.
func (ctx *RuntimeContext) getAPIClient() (*client.APIClient, error) {
if ctx.offline {View on GitHub (pinned to 7fd6ef3c07)