sipeed/picoclaw · error
channel manager not configured
Error message
channel manager not configured
What it means
Returned by the reaction tool's callback when the AgentLoop has no channels.Manager wired in. picoclaw injects the manager after construction via al.SetChannelManager (pkg/agent/agent_inject.go:22), but the reaction tool is registered from config regardless, so the callback guards on al.channelManager == nil. If this fires, the 'reaction' tool was enabled but the embedding process never attached a channel manager.
Source
Thrown at pkg/agent/agent_init.go:225
SessionKey: outboundSessionKey,
Scope: outboundScope,
Content: content,
ReplyToMessageID: replyToMessageID,
}
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(View on GitHub (pinned to 49183d7e8d)
Solutions
- Create and start a channels.Manager (channels.NewManager + RegisterChannel + StartAll) and pass it via al.SetChannelManager(cm) before al.Run(ctx)
- If channels are intentionally unused, remove 'reaction' from the enabled tools in config so the tool is never registered
- Fix startup ordering: build manager -> register/start channels -> SetChannelManager -> Run
- Add a startup smoke test that dispatches a reaction to a scratch channel and asserts no error
Example fix
// before
al := agent.NewAgentLoop(cfg, ...)
go al.Run(ctx) // reaction tool enabled in cfg, no channel manager
// after
al := agent.NewAgentLoop(cfg, ...)
cm, err := channels.NewManager(cfg, msgBus, mediaStore)
if err != nil {
return err
}
cm.RegisterChannel("telegram", telegramChannel)
if err := cm.StartAll(ctx); err != nil {
return err
}
al.SetChannelManager(cm)
go al.Run(ctx) Defensive patterns
Strategy: validation
Validate before calling
cm, err := channels.NewManager(cfg, msgBus, mediaStore)
if err != nil {
return fmt.Errorf("create channel manager: %w", err)
}
if err := cm.StartAll(ctx); err != nil {
return fmt.Errorf("start channels: %w", err)
}
al.SetChannelManager(cm) // must happen before al.Run when channel tools are enabled
if cfg.Tools.IsToolEnabled("reaction") || cfg.Tools.IsToolEnabled("message") {
if cm == nil {
return fmt.Errorf("channel-bound tools enabled but no channel manager wired")
}
} Prevention
- Always call SetChannelManager before Run when channel-bound tools (reaction, message, send_file) are enabled
- In headless/direct mode, strip channel-bound tools from the config so the guard can never trip
- Add a startup assertion that fails fast on nil channel manager instead of failing at first tool call
When it happens
Trigger: Config enables the 'reaction' tool (cfg.Tools.IsToolEnabled("reaction")) and the model invokes it while SetChannelManager was never called (or called with nil) — e.g. running the loop headless with only the message bus, or starting dispatch before channel setup finished.
Common situations: Embedding picoclaw in direct/CLI mode without channels but keeping the default tool list; tests constructing an AgentLoop by hand and forgetting the inject calls; startup-ordering bugs where al.Run starts before channels are registered.
Related errors
- channel %s not found
- 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/c20abc30bfe2631c.
Report an issue: GitHub.