larksuite/cli · error
[%d] %s
Error message
[%d] %s
What it means
This error means the bot-info endpoint returned HTTP 2xx and the body parsed, but the Lark envelope carries a non-zero business code — the API-level failure signal. Unlike the >=400 case, this is a well-formed Lark error response on a success status, e.g. invalid token, permission denied, or app not found, with the authoritative Lark code and message.
Source
Thrown at internal/identitydiag/diagnostics.go:430
AppName string `json:"app_name"`
} `json:"bot"`
}
parseErr := json.Unmarshal(body, &envelope)
if resp.StatusCode >= 400 {
// Lark error responses are usually `{code, msg}` envelopes even on
// non-2xx — surface them when present so callers see why bot auth
// was rejected, not just the bare HTTP code.
if parseErr == nil && envelope.Code != 0 {
return nil, fmt.Errorf("HTTP %d: [%d] %s", resp.StatusCode, envelope.Code, envelope.Msg)
}
return nil, fmt.Errorf("HTTP %d", resp.StatusCode)
}
if parseErr != nil {
return nil, fmt.Errorf("parse response: %w", parseErr)
}
if envelope.Code != 0 {
return nil, fmt.Errorf("[%d] %s", envelope.Code, envelope.Msg)
}
if envelope.Data.OpenID == "" {
return nil, errors.New("open_id is empty")
}
return &botInfo{OpenID: envelope.Data.OpenID, AppName: envelope.Data.AppName}, nil
}
func fillTokenFields(id *Identity, token *larkauth.StoredUAToken) {
id.TokenStatus = larkauth.TokenStatus(token)
id.Scope = token.Scope
id.ExpiresAt = formatMillis(token.ExpiresAt)
id.RefreshExpiresAt = formatMillis(token.RefreshExpiresAt)
id.GrantedAt = formatMillis(token.GrantedAt)
}
func formatMillis(ms int64) string {
if ms <= 0 {
return ""View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Look up the Lark error code in the message ([code]) against Lark's error-code documentation to identify the exact auth/permission issue.
- For token errors, re-authenticate: run the CLI login/token refresh flow so a fresh app/tenant access token is issued.
- Verify the app has the bot capability and required scopes (e.g. contact/app info scopes) granted in the developer console.
- Re-run identity diagnostics to confirm the envelope code is 0 and bot info resolves.
Defensive patterns
Strategy: try-catch
Validate before calling
if token == nil || token.AccessToken == "" {
return errors.New("no access token available; run auth login first")
} Try / catch
info, err := fetchBotInfo(ctx, f, cfg, token)
if err != nil {
msg := err.Error()
if strings.HasPrefix(msg, "[") {
switch {
case strings.Contains(msg, "99991663"), strings.Contains(msg, "99991661"):
return fmt.Errorf("invalid/expired token: %w", err) // trigger re-auth
default:
return fmt.Errorf("Lark API rejected bot info request: %w", err)
}
}
return err
} Prevention
- Check the Lark error-code table first — the [code] in the message is authoritative.
- Grant the app all required bot scopes before running identity diagnostics.
- Keep tokens fresh via the CLI's credential refresh flow.
- Confirm app availability in the target tenant, not just existence in the console.
When it happens
Trigger: fetchBotInfo receives a 2xx response, parses it successfully, and envelope.Code != 0. Reached from diagnoseBot or diagnoseExternalBot during identity diagnostics.
Common situations: App access token invalid or expired (code 99991663/99991661/99991668); app lacking required scopes/permissions for bot info; app not available in the tenant; invalid param errors from API-side validation.
Related errors
- HTTP %d: [%d] %s
- {json.dumps(envelope, ensure_ascii=False)}
- user_info API error: [%d] %s
- connection check: api error code=%d msg=%q
- fetch bot info: HTTP %d
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/66dbcd3da9acc20f.
Report an issue: GitHub.