{"record":{"id":"368cb83f9a784aa8","repo":"larksuite/cli","slug":"botinfo-not-available-runtime-context-not-fully-i","errorCode":null,"errorMessage":"BotInfo not available (runtime context not fully initialized)","messagePattern":"BotInfo not available \\(runtime context not fully initialized\\)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/common/runner.go","lineNumber":153,"sourceCode":"\tlang, _ := i18n.Parse(string(ctx.Config.Lang))\n\treturn lang\n}\n\n// BotInfo holds bot identity metadata fetched lazily from /bot/v3/info.\ntype BotInfo struct {\n\tOpenID  string\n\tAppName string\n}\n\n// BotInfo returns the bot's open_id and display name, fetched lazily from /bot/v3/info.\n// Unlike UserOpenId() (which reads from config), this requires a network call and may fail.\n// Thread-safe via sync.OnceValues; the API is called at most once per RuntimeContext.\nfunc (ctx *RuntimeContext) BotInfo() (*BotInfo, error) {\n\tif ctx.offline {\n\t\treturn nil, errs.NewValidationError(errs.SubtypeFailedPrecondition, \"BotInfo is unavailable during dry-run\")\n\t}\n\tif ctx.botInfoFunc == nil {\n\t\treturn nil, fmt.Errorf(\"BotInfo not available (runtime context not fully initialized)\")\n\t}\n\treturn ctx.botInfoFunc()\n}\n\n// fetchBotInfo calls /bot/v3/info using bot identity and parses the response.\nfunc (ctx *RuntimeContext) fetchBotInfo() (*BotInfo, error) {\n\tif !ctx.Config.CanBot() {\n\t\treturn nil, fmt.Errorf(\"fetch bot info: bot identity is not available in current credential context\")\n\t}\n\tresp, err := ctx.DoAPIAsBot(&larkcore.ApiReq{\n\t\tHttpMethod: http.MethodGet,\n\t\tApiPath:    \"/open-apis/bot/v3/info\",\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"fetch bot info: %w\", err)\n\t}\n\tif resp.StatusCode >= 400 {\n\t\treturn nil, fmt.Errorf(\"fetch bot info: HTTP %d\", resp.StatusCode)","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/common/runner.go#L135-L171","documentation":"BotInfo() lazily fetches the bot's identity (/bot/v3/info) at most once per RuntimeContext via sync.OnceValues. This error means the RuntimeContext was constructed without a botInfoFunc, so the library cannot fetch bot identity at all. It signals a programming/wiring problem: the caller is using bot identity in a context that never configured it.","triggerScenarios":"Calling BotInfo() (directly or via selfAttendeeId / meetingEventsCurrentIdentity) on a RuntimeContext whose botInfoFunc field is nil — e.g. a context built by a test factory or a minimal runtime path that only wires user (tenant) credentials.","commonSituations":"Shortcut code calling ctx.BotInfo() under a runtime built without bot wiring; unit tests using cmdutil.TestFactory defaults; dry-run paths that also lack botInfoFunc (though those normally get the dry-run validation error first).","solutions":["Ensure the RuntimeContext is constructed with a botInfoFunc (the standard runtime setup wires fetchBotInfo); use the normal runtime constructor rather than a minimal/test one for code paths that need bot identity","Check whether the calling shortcut should require bot identity at all; gate on identity availability or surface a typed failed-precondition error to the user instead of relying on the internal error","If in tests, inject a stub botInfoFunc or assert the typed error rather than the plain message"],"exampleFix":"// before\ninfo, err := ctx.BotInfo() // panics into 'not fully initialized' in tests\n// after\nif ctx.BotInfoAvailable() { info, err = ctx.BotInfo() } else { return errs.NewValidationError(errs.SubtypeFailedPrecondition, \"bot identity required\") }","handlingStrategy":"validation","validationCode":"if ctx.FileIO == nil && needsBot { /* check wiring */ }\n// Only call when the runtime was built with bot wiring:\ninfo, err := ctx.BotInfo()\nif err != nil && strings.Contains(err.Error(), \"not fully initialized\") { /* wrong runtime constructor */ }","typeGuard":"func botInfoAvailable(ctx *common.RuntimeContext) bool {\n\t_, err := ctx.BotInfo()\n\treturn err == nil || !strings.Contains(err.Error(), \"not fully initialized\")\n}","tryCatchPattern":"info, err := ctx.BotInfo()\nif err != nil {\n\tif strings.Contains(err.Error(), \"not fully initialized\") {\n\t\treturn errs.NewValidationError(errs.SubtypeFailedPrecondition, \"bot identity unavailable in this runtime\")\n\t}\n\treturn err\n}","preventionTips":["Always construct RuntimeContext via the standard factory that wires botInfoFunc","Keep bot-dependent shortcuts out of minimal/test runtime paths, or inject a stub botInfoFunc in tests","Prefer the typed dry-run/failed-precondition errors BotInfo already returns over ad hoc checks"],"tags":["go","bot-identity","runtime-context","initialization"],"backgroundTag":"runtime-context-not-initialized","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"}