sipeed/picoclaw · warning
failed to close discord session: %w
Error message
failed to close discord session: %w
What it means
Stop() reports this when session.Close() errors while tearing down the Discord websocket. By this point the channel is already non-running (SetRunning(false)), typing goroutines and contexts are canceled, so this is best-effort cleanup noise — typically 'use of closed connection' or a failed websocket close handshake.
Source
Thrown at pkg/channels/discord/discord.go:158
// Stop all typing goroutines before closing session
c.typingMu.Lock()
for chatID, stop := range c.typingStop {
close(stop)
delete(c.typingStop, chatID)
}
c.typingMu.Unlock()
// Cancel our context so typing goroutines using c.ctx.Done() exit
if c.cancel != nil {
c.cancel()
}
if c.progress != nil {
c.progress.StopAll()
}
if err := c.session.Close(); err != nil {
return fmt.Errorf("failed to close discord session: %w", err)
}
return nil
}
func (c *DiscordChannel) Send(ctx context.Context, msg bus.OutboundMessage) ([]string, error) {
if !c.IsRunning() {
return nil, channels.ErrNotRunning
}
channelID := msg.ChatID
if channelID == "" {
return nil, fmt.Errorf("channel ID is empty")
}
if len([]rune(msg.Content)) == 0 {
return nil, nil
}View on GitHub (pinned to 49183d7e8d)
Solutions
- Treat Stop errors as non-fatal: log a warning and continue shutdown
- Guard against double Stop with an IsRunning/once check before closing the session
- If the process is exiting anyway, a failed Close is harmless — the OS reclaims the socket
Example fix
// before
if err := c.session.Close(); err != nil {
return fmt.Errorf("failed to close discord session: %w", err)
}
// after
if err := c.session.Close(); err != nil {
logger.WarnCF("discord", "session close error (ignored)", map[string]any{"error": err.Error()})
}
return nil Defensive patterns
Strategy: fallback
Try / catch
if err := ch.Stop(ctx); err != nil {
// shutdown is best-effort: log and continue teardown
log.Printf("warn: discord stop: %v", err)
} Prevention
- Guard Stop against double invocation (check IsRunning or use sync.Once)
- Treat close errors as warnings in shutdown paths — the socket is reclaimed at process exit anyway
- Stop channels in dependency order so voice/typing goroutines finish before session.Close()
When it happens
Trigger: Stop called twice (second Close errors), stopping after the network/voice connection already dropped, or the websocket close handshake failing during shutdown.
Common situations: Double-stop from manager plus signal handler, shutdown after network loss, orchestrators that call Stop on both SIGTERM and cleanup.
Related errors
- failed to open discord session: %w
- events: bus is closed
- deltachat rpc: connection closed
- failed to start stream client: %w
- failed to create discord session: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/919a4e1dfcbe4faf.
Report an issue: GitHub.