{"record":{"id":"357015b00b34f9cf","repo":"larksuite/cli","slug":"fetch-bot-info-d-s","errorCode":null,"errorMessage":"fetch bot info: [%d] %s","messagePattern":"fetch bot info: \\[(.+?)\\] (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/common/runner.go","lineNumber":187,"sourceCode":"\t}\n\tif resp.StatusCode >= 400 {\n\t\treturn nil, fmt.Errorf(\"fetch bot info: HTTP %d\", resp.StatusCode)\n\t}\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\tif err := json.Unmarshal(resp.RawBody, &envelope); err != nil {\n\t\treturn nil, fmt.Errorf(\"fetch bot info: unmarshal: %w\", err)\n\t}\n\tif envelope.Code != 0 {\n\t\treturn nil, fmt.Errorf(\"fetch bot info: [%d] %s\", envelope.Code, envelope.Msg)\n\t}\n\tif envelope.Data.OpenID == \"\" {\n\t\treturn nil, fmt.Errorf(\"fetch bot info: open_id is empty\")\n\t}\n\treturn &BotInfo{OpenID: envelope.Data.OpenID, AppName: envelope.Data.AppName}, nil\n}\n\n// Ctx returns the context.Context propagated from cmd.Context().\nfunc (ctx *RuntimeContext) Ctx() context.Context { return ctx.ctx }\n\n// getAPIClient returns the cached APIClient, creating it on first use.\n// Thread-safe via sync.OnceValues (initialized in newRuntimeContext).\n// Falls back to direct construction for test contexts that bypass newRuntimeContext.\nfunc (ctx *RuntimeContext) getAPIClient() (*client.APIClient, error) {\n\tif ctx.offline {\n\t\treturn nil, errs.NewValidationError(errs.SubtypeFailedPrecondition, \"OpenAPI requests are unavailable during dry-run\")\n\t}\n\tif ctx.apiClientFunc != nil {","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/common/runner.go#L169-L205","documentation":"The /bot/v3/info envelope decoded fine but carries a non-zero business code, meaning the Lark API itself rejected the logical request. The message surfaces the API's own code and msg so the developer can map it to Lark's error taxonomy (e.g. permission denied, invalid token).","triggerScenarios":"envelope.Code != 0 in the bot info response — e.g. invalid app access token, bot capability disabled for the app, or tenant-level restriction on bot info.","commonSituations":"Token mismatched to tenant/app; app not published/enabled in the tenant; insufficient bot scopes for /bot/v3/info.","solutions":["Look up the returned code in Lark's API error docs and apply the mapped fix (scopes, token, app state)","Regenerate/refresh the app access token for the bot identity","Confirm the app is enabled and bot capability is turned on in the developer console"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"info, err := ctx.BotInfo()\nif err != nil {\n\tvar apiErr *lark.APIError\n\tif errors.As(err, &apiErr) { /* map apiErr.Code via Lark docs */ }\n\tif strings.Contains(err.Error(), \"fetch bot info: [\"){ /* business code in message: surface to user */ }\n\treturn err\n}","preventionTips":["Map non-zero Lark business codes to concrete remediation (scopes, token, app state)","Keep app access tokens current and tenant-scoped","Confirm the app is published/enabled in the tenant before bot calls"],"tags":["go","lark-api","business-error","bot-identity"],"backgroundTag":"lark-business-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"}