{"record":{"id":"a4e175f1fdb61de1","repo":"sipeed/picoclaw","slug":"feishu-app-id-or-app-secret-is-empty","errorCode":null,"errorMessage":"feishu app_id or app_secret is empty","messagePattern":"feishu app_id or app_secret is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/channels/feishu/feishu_64.go","lineNumber":92,"sourceCode":"\t}\n\tch := &FeishuChannel{\n\t\tBaseChannel: base,\n\t\tbc:          bc,\n\t\tconfig:      cfg,\n\t\ttokenCache:  tc,\n\t\tclient:      lark.NewClient(cfg.AppID, cfg.AppSecret.String(), opts...),\n\t}\n\tch.deleteMessageFn = ch.deleteMessageAPI\n\tch.sendMediaPartFn = ch.sendMediaPart\n\tch.sendTextFn = ch.sendText\n\tch.progress = channels.NewToolFeedbackAnimator(ch.EditMessage)\n\tch.SetOwner(ch)\n\treturn ch, nil\n}\n\nfunc (c *FeishuChannel) Start(ctx context.Context) error {\n\tif c.config.AppID == \"\" || c.config.AppSecret.String() == \"\" {\n\t\treturn fmt.Errorf(\"feishu app_id or app_secret is empty\")\n\t}\n\n\t// Fetch bot open_id via API for reliable @mention detection.\n\tif err := c.fetchBotOpenID(ctx); err != nil {\n\t\tlogger.ErrorCF(\"feishu\", \"Failed to fetch bot open_id, @mention detection may not work\", map[string]any{\n\t\t\t\"error\": err.Error(),\n\t\t})\n\t}\n\n\tdispatcher := larkdispatcher.NewEventDispatcher(c.config.VerificationToken.String(), c.config.EncryptKey.String()).\n\t\tOnP2MessageReceiveV1(c.handleMessageReceive)\n\n\trunCtx, cancel := context.WithCancel(ctx)\n\n\tc.mu.Lock()\n\tc.cancel = cancel\n\tdomain := lark.FeishuBaseUrl\n\tif c.config.IsLark {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/feishu/feishu_64.go#L74-L110","documentation":"FeishuChannel.Start refuses to boot when either config.AppID or the resolved config.AppSecret is an empty string. It is a fail-fast guard before any Feishu API traffic, including the bot open_id fetch and the event dispatcher setup. This is a configuration error and is never transient.","triggerScenarios":"NewFeishuChannel was built from a config whose AppID or AppSecret resolved to empty (unset env var, blank YAML field, secret loader returning an empty value), then Start(ctx) is called.","commonSituations":"Missing FEISHU_APP_ID/FEISHU_APP_SECRET in .env or deployment secrets; typo'd env var name so the config decodes to empty; secret manager path returns empty without failing; sample config copied without filling credentials.","solutions":["Set both app_id and app_secret in the feishu channel config (Feishu Open Platform 'Credentials & Basic Info' page)","Verify the exact env var / config keys your loader reads and that the secret resolves non-empty (log len, never the value)","Fail fast at process startup: validate config before starting the channel so the bot does not run half-alive","If using a secret backend, check the mounted key path and permissions"],"exampleFix":"// before\nch, _ := feishu.NewFeishuChannel(cfg)\n_ = ch.Start(ctx) // error surfaces late, bot silently down\n\n// after\nif cfg.AppID == \"\" || cfg.AppSecret.String() == \"\" {\n\tlog.Fatal(\"feishu: app_id/app_secret not configured\")\n}\nch, err := feishu.NewFeishuChannel(cfg)\nif err != nil {\n\tlog.Fatal(err)\n}\nif err := ch.Start(ctx); err != nil {\n\tlog.Fatal(err)\n}","handlingStrategy":"validation","validationCode":"func feishuConfigValid(cfg feishu.Config) error {\n\tif cfg.AppID == \"\" {\n\t\treturn errors.New(\"feishu config: app_id is empty\")\n\t}\n\tif cfg.AppSecret.String() == \"\" {\n\t\treturn errors.New(\"feishu config: app_secret is empty\")\n\t}\n\treturn nil\n}\n\n// run BEFORE constructing/starting the channel\nif err := feishuConfigValid(cfg); err != nil {\n\tlog.Fatal(err)\n}","typeGuard":"null","tryCatchPattern":"if err := ch.Start(ctx); err != nil {\n\tif strings.Contains(err.Error(), \"app_id or app_secret is empty\") {\n\t\t// config problem: stop the process, do not retry\n\t\tlog.Fatal(\"fix feishu credentials: \", err)\n\t}\n\treturn err\n}","preventionTips":["Validate required secrets at process start, not on first message","Log secret NAME and emptiness, never the value","Use startup smoke tests in CI with dummy configs to catch missing-key paths","Prefer failing the whole process over a silently disabled channel"],"tags":["feishu","config","credentials","validation","startup"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}