{"record":{"id":"09cf756f1079c942","repo":"sipeed/picoclaw","slug":"failed-to-open-discord-session-w","errorCode":null,"errorMessage":"failed to open discord session: %w","messagePattern":"failed to open discord session: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/channels/discord/discord.go","lineNumber":124,"sourceCode":"\nfunc (c *DiscordChannel) Start(ctx context.Context) error {\n\tlogger.InfoC(\"discord\", \"Starting Discord bot\")\n\n\tc.ctx, c.cancel = context.WithCancel(ctx)\n\n\t// Get bot user ID before opening session to avoid race condition\n\tbotUser, err := c.session.User(\"@me\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get bot user: %w\", err)\n\t}\n\tc.botUserID = botUser.ID\n\n\tc.session.AddHandler(c.handleMessage)\n\n\tgo c.listenVoiceControl(c.ctx)\n\n\tif err := c.session.Open(); err != nil {\n\t\treturn fmt.Errorf(\"failed to open discord session: %w\", err)\n\t}\n\n\tc.SetRunning(true)\n\n\tlogger.InfoCF(\"discord\", \"Discord bot connected\", map[string]any{\n\t\t\"username\": botUser.Username,\n\t\t\"user_id\":  botUser.ID,\n\t})\n\n\treturn nil\n}\n\nfunc (c *DiscordChannel) Stop(ctx context.Context) error {\n\tlogger.InfoC(\"discord\", \"Stopping Discord bot\")\n\tc.SetRunning(false)\n\n\t// Stop all typing goroutines before closing session\n\tc.typingMu.Lock()","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/discord/discord.go#L106-L142","documentation":"session.Open() failed while establishing the Discord WebSocket gateway connection. It fires after credentials already validated (User(\"@me\") succeeded), so the cause is gateway-specific: network/proxy blocking wss, Discord gateway outage, or a session problem — not the token itself.","triggerScenarios":"Start() when egress to gateway.discord.gg:443 (websocket) is blocked while REST works, a proxy that does not support websocket upgrades, Discord outage/maintenance on the gateway, or calling Start on an already-open session.","commonSituations":"Corporate firewalls allowing HTTPS APIs but killing long-lived websockets, HTTP-only proxies applied via cfg.Proxy or env, Discord status incidents, restarting the channel twice without Stop.","solutions":["Confirm websocket-capable egress to gateway.discord.gg:443 (test with a websocket client or wscat)","Remove or replace proxies that cannot tunnel wss; verify socks5/http CONNECT works","Check status.discord.com during incidents and retry Start with backoff","Ensure Start is only called once per session lifecycle (Stop between restarts)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Confirm websocket egress before Start (gateway reachable?)\n// quick probe: TLS connect to gateway.discord.gg:443\nconn, err := net.DialTimeout(\"tcp\", \"gateway.discord.gg:443\", 5*time.Second)\nif err != nil {\n    return fmt.Errorf(\"cannot reach discord gateway: %w\", err)\n}\nconn.Close()","typeGuard":null,"tryCatchPattern":"err := backoff.Retry(func() error {\n    if err := ch.Start(ctx); err != nil {\n        if strings.Contains(err.Error(), \"failed to open discord session\") {\n            return fmt.Errorf(\"gateway open: %w\", err) // retryable\n        }\n        return backoff.Permanent(err)\n    }\n    return nil\n}, backoff.NewExponentialBackOff())","preventionTips":["Ensure the proxy (cfg.Proxy or HTTP(S)_PROXY) supports websocket upgrades / CONNECT","Check status.discord.com during incidents instead of tight-loop retrying","Call Start only once per session; Stop between restarts","Enable required privileged intents in the Developer Portal so the gateway does not reject the session"],"tags":["discord","websocket","gateway","startup","network"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}