sipeed/picoclaw · critical
feishu app_id or app_secret is empty
Error message
feishu app_id or app_secret is empty
What it means
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.
Source
Thrown at pkg/channels/feishu/feishu_64.go:92
}
ch := &FeishuChannel{
BaseChannel: base,
bc: bc,
config: cfg,
tokenCache: tc,
client: lark.NewClient(cfg.AppID, cfg.AppSecret.String(), opts...),
}
ch.deleteMessageFn = ch.deleteMessageAPI
ch.sendMediaPartFn = ch.sendMediaPart
ch.sendTextFn = ch.sendText
ch.progress = channels.NewToolFeedbackAnimator(ch.EditMessage)
ch.SetOwner(ch)
return ch, nil
}
func (c *FeishuChannel) Start(ctx context.Context) error {
if c.config.AppID == "" || c.config.AppSecret.String() == "" {
return fmt.Errorf("feishu app_id or app_secret is empty")
}
// Fetch bot open_id via API for reliable @mention detection.
if err := c.fetchBotOpenID(ctx); err != nil {
logger.ErrorCF("feishu", "Failed to fetch bot open_id, @mention detection may not work", map[string]any{
"error": err.Error(),
})
}
dispatcher := larkdispatcher.NewEventDispatcher(c.config.VerificationToken.String(), c.config.EncryptKey.String()).
OnP2MessageReceiveV1(c.handleMessageReceive)
runCtx, cancel := context.WithCancel(ctx)
c.mu.Lock()
c.cancel = cancel
domain := lark.FeishuBaseUrl
if c.config.IsLark {View on GitHub (pinned to 49183d7e8d)
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
Example fix
// before
ch, _ := feishu.NewFeishuChannel(cfg)
_ = ch.Start(ctx) // error surfaces late, bot silently down
// after
if cfg.AppID == "" || cfg.AppSecret.String() == "" {
log.Fatal("feishu: app_id/app_secret not configured")
}
ch, err := feishu.NewFeishuChannel(cfg)
if err != nil {
log.Fatal(err)
}
if err := ch.Start(ctx); err != nil {
log.Fatal(err)
} Defensive patterns
Strategy: validation
Validate before calling
func feishuConfigValid(cfg feishu.Config) error {
if cfg.AppID == "" {
return errors.New("feishu config: app_id is empty")
}
if cfg.AppSecret.String() == "" {
return errors.New("feishu config: app_secret is empty")
}
return nil
}
// run BEFORE constructing/starting the channel
if err := feishuConfigValid(cfg); err != nil {
log.Fatal(err)
} Type guard
null
Try / catch
if err := ch.Start(ctx); err != nil {
if strings.Contains(err.Error(), "app_id or app_secret is empty") {
// config problem: stop the process, do not retry
log.Fatal("fix feishu credentials: ", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- dingtalk client_id and client_secret are required
- irc server is required
- irc nick is required
- line channel_secret and channel_access_token are required
- QQ app_id and app_secret not configured
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/a4e175f1fdb61de1.
Report an issue: GitHub.