sipeed/picoclaw · error
irc connect failed: %w
Error message
irc connect failed: %w
What it means
The initial conn.Connect() to the IRC server failed; the underlying ircevent error is wrapped with %w. This covers only the first connection — once connected, conn.Loop() handles reconnection internally, so the error means the channel never came up (DNS failure, refused connection, TLS handshake failure, SASL rejection).
Source
Thrown at pkg/channels/irc/irc.go:102
}
}
// SASL auth (takes priority over NickServ)
if c.config.SASLUser != "" && c.config.SASLPassword.String() != "" {
conn.SASLLogin = c.config.SASLUser
conn.SASLPassword = c.config.SASLPassword.String()
}
// Register event handlers
conn.AddConnectCallback(func(e ircmsg.Message) {
c.onConnect(conn)
})
conn.AddCallback("PRIVMSG", func(e ircmsg.Message) {
c.onPrivmsg(conn, e)
})
if err := conn.Connect(); err != nil {
return fmt.Errorf("irc connect failed: %w", err)
}
c.conn = conn
// ircevent.Connection.Loop() handles reconnection internally.
go conn.Loop()
c.SetRunning(true)
logger.InfoCF("irc", "IRC channel started", map[string]any{
"server": c.config.Server,
"nick": c.config.Nick,
})
return nil
}
// Stop disconnects from the IRC server.
func (c *IRCChannel) Stop(ctx context.Context) error {
logger.InfoC("irc", "Stopping IRC channel")View on GitHub (pinned to 49183d7e8d)
Solutions
- Dial manually from the same host: nc -vz irc.example.com 6697 (or openssl s_client -connect host:6697) to isolate network vs auth.
- Check the TLS setting matches the port: TLS on 6697, plaintext on 6667; mispairing produces handshake/connection errors.
- If SASL is configured, verify credentials — some networks fail the connect at SASL negotiation.
- Wrap channel Start in a bounded retry loop, because ircevent's auto-reconnect only kicks in after a first successful connect (see exampleFix).
Example fix
// before — channel dead if IRC is unreachable at boot
if err := ch.Start(ctx); err != nil { return err }
// after — bounded boot-time retry
var err error
for attempt := 1; attempt <= 5; attempt++ {
if err = ch.Start(ctx); err == nil { break }
select {
case <-ctx.Done(): return ctx.Err()
case <-time.After(time.Duration(attempt) * 2 * time.Second):
}
} Defensive patterns
Strategy: retry
Validate before calling
host, port, serr := net.SplitHostPort(cfg.Server)
if serr != nil {
return fmt.Errorf("irc server must be host:port, got %q", cfg.Server)
}
if conn, derr := net.DialTimeout("tcp", net.JoinHostPort(host, port), 3*time.Second); derr != nil {
return fmt.Errorf("irc server unreachable: %w", derr)
} else {
conn.Close()
} Type guard
func isIRCConnectErr(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "irc connect failed:")
} Try / catch
if err := ch.Start(ctx); err != nil {
if isIRCConnectErr(err) {
// initial dial failed; ircevent only auto-reconnects AFTER a first success,
// so retry Start with backoff until the network is up
retryWithBackoff(ctx, func() error { return ch.Start(ctx) })
}
} Prevention
- Match TLS flag to port (6697 TLS / 6667 plain)
- Verify SASL credentials before relying on them
- Add boot-time retry for the first connect in k8s where CNI may lag
- Smoke-test connectivity with nc/openssl from the same host
When it happens
Trigger: TCP dial to server:port fails (wrong host/port, firewall); TLS expected on a plaintext port or vice versa (6697 vs 6667 mismatch); SASL credentials rejected at connect; DNS not resolvable from the container.
Common situations: Boot-time network not ready in k8s (CNI race); port/transport mismatch in config; IRC network blocking the host (killed after abuse, D-lines for cloud IPs); corporate firewall dropping 6667/6697.
Related errors
- refreshing token: %w
- exchanging code for tokens: %w
- after %d retries: %w
- error fetching models: %w
- failed to get WeCom QR code: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/5f6f97bac47bc885.
Report an issue: GitHub.