sipeed/picoclaw · error

failed to open discord session: %w

Error message

failed to open discord session: %w

What it means

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.

Source

Thrown at pkg/channels/discord/discord.go:124

func (c *DiscordChannel) Start(ctx context.Context) error {
	logger.InfoC("discord", "Starting Discord bot")

	c.ctx, c.cancel = context.WithCancel(ctx)

	// Get bot user ID before opening session to avoid race condition
	botUser, err := c.session.User("@me")
	if err != nil {
		return fmt.Errorf("failed to get bot user: %w", err)
	}
	c.botUserID = botUser.ID

	c.session.AddHandler(c.handleMessage)

	go c.listenVoiceControl(c.ctx)

	if err := c.session.Open(); err != nil {
		return fmt.Errorf("failed to open discord session: %w", err)
	}

	c.SetRunning(true)

	logger.InfoCF("discord", "Discord bot connected", map[string]any{
		"username": botUser.Username,
		"user_id":  botUser.ID,
	})

	return nil
}

func (c *DiscordChannel) Stop(ctx context.Context) error {
	logger.InfoC("discord", "Stopping Discord bot")
	c.SetRunning(false)

	// Stop all typing goroutines before closing session
	c.typingMu.Lock()

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Confirm websocket-capable egress to gateway.discord.gg:443 (test with a websocket client or wscat)
  2. Remove or replace proxies that cannot tunnel wss; verify socks5/http CONNECT works
  3. Check status.discord.com during incidents and retry Start with backoff
  4. Ensure Start is only called once per session lifecycle (Stop between restarts)
Defensive patterns

Strategy: retry

Validate before calling

// Confirm websocket egress before Start (gateway reachable?)
// quick probe: TLS connect to gateway.discord.gg:443
conn, err := net.DialTimeout("tcp", "gateway.discord.gg:443", 5*time.Second)
if err != nil {
    return fmt.Errorf("cannot reach discord gateway: %w", err)
}
conn.Close()

Try / catch

err := backoff.Retry(func() error {
    if err := ch.Start(ctx); err != nil {
        if strings.Contains(err.Error(), "failed to open discord session") {
            return fmt.Errorf("gateway open: %w", err) // retryable
        }
        return backoff.Permanent(err)
    }
    return nil
}, backoff.NewExponentialBackOff())

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/09cf756f1079c942. Report an issue: GitHub.