{"record":{"id":"5f6f97bac47bc885","repo":"sipeed/picoclaw","slug":"irc-connect-failed-w","errorCode":null,"errorMessage":"irc connect failed: %w","messagePattern":"irc connect failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/channels/irc/irc.go","lineNumber":102,"sourceCode":"\t\t}\n\t}\n\n\t// SASL auth (takes priority over NickServ)\n\tif c.config.SASLUser != \"\" && c.config.SASLPassword.String() != \"\" {\n\t\tconn.SASLLogin = c.config.SASLUser\n\t\tconn.SASLPassword = c.config.SASLPassword.String()\n\t}\n\n\t// Register event handlers\n\tconn.AddConnectCallback(func(e ircmsg.Message) {\n\t\tc.onConnect(conn)\n\t})\n\tconn.AddCallback(\"PRIVMSG\", func(e ircmsg.Message) {\n\t\tc.onPrivmsg(conn, e)\n\t})\n\n\tif err := conn.Connect(); err != nil {\n\t\treturn fmt.Errorf(\"irc connect failed: %w\", err)\n\t}\n\n\tc.conn = conn\n\n\t// ircevent.Connection.Loop() handles reconnection internally.\n\tgo conn.Loop()\n\n\tc.SetRunning(true)\n\tlogger.InfoCF(\"irc\", \"IRC channel started\", map[string]any{\n\t\t\"server\": c.config.Server,\n\t\t\"nick\":   c.config.Nick,\n\t})\n\treturn nil\n}\n\n// Stop disconnects from the IRC server.\nfunc (c *IRCChannel) Stop(ctx context.Context) error {\n\tlogger.InfoC(\"irc\", \"Stopping IRC channel\")","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/irc/irc.go#L84-L120","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before — channel dead if IRC is unreachable at boot\nif err := ch.Start(ctx); err != nil { return err }\n\n// after — bounded boot-time retry\nvar err error\nfor attempt := 1; attempt <= 5; attempt++ {\n    if err = ch.Start(ctx); err == nil { break }\n    select {\n    case <-ctx.Done(): return ctx.Err()\n    case <-time.After(time.Duration(attempt) * 2 * time.Second):\n    }\n}","handlingStrategy":"retry","validationCode":"host, port, serr := net.SplitHostPort(cfg.Server)\nif serr != nil {\n    return fmt.Errorf(\"irc server must be host:port, got %q\", cfg.Server)\n}\nif conn, derr := net.DialTimeout(\"tcp\", net.JoinHostPort(host, port), 3*time.Second); derr != nil {\n    return fmt.Errorf(\"irc server unreachable: %w\", derr)\n} else {\n    conn.Close()\n}","typeGuard":"func isIRCConnectErr(err error) bool {\n    return err != nil && strings.HasPrefix(err.Error(), \"irc connect failed:\")\n}","tryCatchPattern":"if err := ch.Start(ctx); err != nil {\n    if isIRCConnectErr(err) {\n        // initial dial failed; ircevent only auto-reconnects AFTER a first success,\n        // so retry Start with backoff until the network is up\n        retryWithBackoff(ctx, func() error { return ch.Start(ctx) })\n    }\n}","preventionTips":["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"],"tags":["irc","network","go","connect","tls"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}