{"record":{"id":"ed5569daa8bbfd01","repo":"larksuite/cli","slug":"http-d-d-s","errorCode":null,"errorMessage":"HTTP %d: [%d] %s","messagePattern":"HTTP (.+?): \\[(.+?)\\] (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/identitydiag/diagnostics.go","lineNumber":422,"sourceCode":"\tbody, _ := io.ReadAll(resp.Body)\n\t// /open-apis/bot/v3/info returns `{code, msg, bot: {...}}` — the bot\n\t// payload is under \"bot\", not \"data\" as the newer Lark API convention.\n\tvar envelope struct {\n\t\tCode int    `json:\"code\"`\n\t\tMsg  string `json:\"msg\"`\n\t\tData struct {\n\t\t\tOpenID  string `json:\"open_id\"`\n\t\t\tAppName string `json:\"app_name\"`\n\t\t} `json:\"bot\"`\n\t}\n\tparseErr := json.Unmarshal(body, &envelope)\n\n\tif resp.StatusCode >= 400 {\n\t\t// Lark error responses are usually `{code, msg}` envelopes even on\n\t\t// non-2xx — surface them when present so callers see why bot auth\n\t\t// was rejected, not just the bare HTTP code.\n\t\tif parseErr == nil && envelope.Code != 0 {\n\t\t\treturn nil, fmt.Errorf(\"HTTP %d: [%d] %s\", resp.StatusCode, envelope.Code, envelope.Msg)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"HTTP %d\", resp.StatusCode)\n\t}\n\tif parseErr != nil {\n\t\treturn nil, fmt.Errorf(\"parse response: %w\", parseErr)\n\t}\n\tif envelope.Code != 0 {\n\t\treturn nil, fmt.Errorf(\"[%d] %s\", envelope.Code, envelope.Msg)\n\t}\n\tif envelope.Data.OpenID == \"\" {\n\t\treturn nil, errors.New(\"open_id is empty\")\n\t}\n\treturn &botInfo{OpenID: envelope.Data.OpenID, AppName: envelope.Data.AppName}, nil\n}\n\nfunc fillTokenFields(id *Identity, token *larkauth.StoredUAToken) {\n\tid.TokenStatus = larkauth.TokenStatus(token)\n\tid.Scope = token.Scope","sourceCodeStart":404,"sourceCodeEnd":440,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/identitydiag/diagnostics.go#L404-L440","documentation":"This error means the Lark API returned an HTTP status >= 400 while fetching bot info, AND the response body parsed into a {code, msg} envelope with a non-zero Lark business code. The error surfaces both the HTTP status and the Lark error code/message so callers can see why bot authentication was rejected — typically an invalid or insufficient app access token — rather than just the bare HTTP code.","triggerScenarios":"fetchBotInfo GETs /open-apis/bot/v3/info; the server responds 4xx/5xx, the body parses as a Lark envelope, parseErr is nil and envelope.Code != 0. Reached from diagnoseBot or diagnoseExternalBot.","commonSituations":"Expired or invalid tenant_access_token/app_access_token (HTTP 400/401 with code 99991663/99991661); app not published or bot capability disabled (tenant has no bot); wrong brand/endpoint pointing at an environment where the app doesn't exist; rate limiting (429).","solutions":["Look up the Lark code in the message (e.g. [99991661]) — for invalid token errors, refresh credentials with the CLI auth/login flow.","Verify the app has bot capability enabled and is published/available in the tenant.","Check that the configured brand/endpoints match the tenant (feishu vs lark) where the app is registered.","Re-run identity diagnostics after fixing auth to confirm the bot info fetch succeeds."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"info, err := fetchBotInfo(ctx, f, cfg, token)\nif err != nil {\n    var codeErr interface{ Error() string }\n    msg := err.Error()\n    if strings.HasPrefix(msg, \"HTTP \") && strings.Contains(msg, \"[\") {\n        // e.g. HTTP 401: [99991661] invalid access token\n        if strings.Contains(msg, \"99991661\") || strings.Contains(msg, \"99991663\") {\n            return fmt.Errorf(\"token rejected, re-authenticate: %w\", err)\n        }\n        return fmt.Errorf(\"bot auth rejected by Lark: %w\", err)\n    }\n    return err\n}","preventionTips":["Refresh app/tenant access tokens before they expire (schedule re-auth).","Enable bot capability and publish the app in the tenant before running diagnostics.","Match the CLI brand configuration (feishu vs lark) to where the app is registered.","Monitor HTTP 429s and back off instead of hammering the endpoint."],"tags":["http","api-error","authentication","lark"],"backgroundTag":"lark-api-error-code","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}