sipeed/picoclaw · error
channel %s not found
Error message
channel %s not found
What it means
The reaction tool found the channel manager but channels.Manager.GetChannel(name) returned false for the name the model passed. GetChannel (pkg/channels/manager.go:1871) is a case-sensitive map lookup over channels registered via RegisterChannel, so the argument must exactly match a registered channel name. The channel argument comes straight from the LLM, so hallucinated, stale, or misspelled names fail here.
Source
Thrown at pkg/agent/agent_init.go:229
}
if al.channelManager != nil && channel != "" {
return al.channelManager.SendMessage(ctx, outboundMessage)
}
pubCtx, pubCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer pubCancel()
return msgBus.PublishOutbound(pubCtx, outboundMessage)
})
agent.Tools.Register(messageTool)
}
if cfg.Tools.IsToolEnabled("reaction") {
reactionTool := tools.NewReactionTool()
reactionTool.SetReactionCallback(func(ctx context.Context, channel, chatID, messageID string) error {
if al.channelManager == nil {
return fmt.Errorf("channel manager not configured")
}
ch, ok := al.channelManager.GetChannel(channel)
if !ok {
return fmt.Errorf("channel %s not found", channel)
}
rc, ok := ch.(channels.ReactionCapable)
if !ok {
return fmt.Errorf("channel %s does not support reactions", channel)
}
_, err := rc.ReactToMessage(ctx, chatID, messageID)
return err
})
agent.Tools.Register(reactionTool)
}
// Send file tool (outbound media via MediaStore — store injected later by SetMediaStore)
if cfg.Tools.IsToolEnabled("send_file") {
sendFileTool := tools.NewSendFileTool(
agent.Workspace,
cfg.Agents.Defaults.RestrictToWorkspace,
cfg.Agents.Defaults.GetMaxMediaSize(),
nil,View on GitHub (pinned to 49183d7e8d)
Solutions
- List registered names via cm.GetStatus() and correct the tool argument or the config so they match exactly (case-sensitive)
- Enable the channel in config (channels.<name>.enabled=true with valid credentials) and restart picoclaw
- If the channel was renamed, restart so RegisterChannel sees the new key, and update prompts that hard-code channel names
- Give the model the valid channel list in its system prompt so it stops guessing
Example fix
// config/config.json — before
"channels": { "telegram": { "enabled": false } }
// after
"channels": { "telegram": { "enabled": true, "token": "..." } } Defensive patterns
Strategy: validation
Validate before calling
for name := range cm.GetStatus() {
log.Printf("registered channel: %s", name)
}
ch, ok := cm.GetChannel(channelName)
if !ok {
return fmt.Errorf("channel %q not registered; fix config or tool argument", channelName)
}
_ = ch // safe to proceed with the reaction Prevention
- Register channels under stable lowercase names and never reuse old names for renamed channels
- Put the exact registered channel names in the agent's system prompt so the model passes valid values
- Restart picoclaw after changing channels config so RegisterChannel state matches config
When it happens
Trigger: The agent calls the reaction tool with channel="Telegram" while the registered name is "telegram"; the channel was renamed/removed in config without a restart; the channel failed init and was never registered into the manager's map.
Common situations: Case mismatch between tool argument and registered name; renaming a channel in config while agent prompts or session history still reference the old name; channel disabled (enabled=false) in config; model typos.
Related errors
- channel manager not configured
- channel %s does not support reactions
- failed to load MCP servers: %w
- tool discovery is enabled but neither 'use_bm25' nor 'use_re
- no default agent for heartbeat
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/161afd3ac4d7956d.
Report an issue: GitHub.