sipeed/picoclaw · error

failed to get websocket info: %w

Error message

failed to get websocket info: %w

What it means

QQChannel.Start calls c.api.WS(c.ctx, nil, "") on the botgo OpenAPI client to fetch the WebSocket gateway URL for the bot's session manager. When that HTTP call fails — auth rejected, network error, or QQ API 5xx — the error is wrapped as "failed to get websocket info". Until this succeeds the channel has no gateway and cannot receive events.

Source

Thrown at pkg/channels/qq/qq.go:141

	// start auto-refresh token goroutine
	if err := token.StartRefreshAccessToken(c.ctx, c.tokenSource); err != nil {
		return fmt.Errorf("failed to start token refresh: %w", err)
	}

	// initialize OpenAPI client
	c.api = botgo.NewOpenAPI(c.config.AppID, c.tokenSource).WithTimeout(5 * time.Second)

	// register event handlers
	intent := event.RegisterHandlers(
		c.handleC2CMessage(),
		c.handleGroupATMessage(),
	)

	// get WebSocket endpoint
	wsInfo, err := c.api.WS(c.ctx, nil, "")
	if err != nil {
		return fmt.Errorf("failed to get websocket info: %w", err)
	}

	logger.InfoCF("qq", "Got WebSocket info", map[string]any{
		"shards": wsInfo.Shards,
	})

	// create and save sessionManager
	c.sessionManager = botgo.NewSessionManager()

	// start WebSocket connection in goroutine to avoid blocking
	go func() {
		if err := c.sessionManager.Start(wsInfo, c.tokenSource, &intent); err != nil {
			logger.ErrorCF("qq", "WebSocket session error", map[string]any{
				"error": err.Error(),
			})
			c.SetRunning(false)
		}
	}()

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Inspect the wrapped error (errors.Unwrap / %v chain) to tell auth failure (fix credentials) from network failure (fix connectivity).
  2. Retry Start with backoff — the WS info call is a plain HTTP GET and commonly succeeds on the second attempt after a transient failure.
  3. Verify the bot application is published/active in the QQ console (unactivated apps can be denied gateway access).
  4. Check egress rules allow https and wss to the QQ open platform endpoints from the host/container.

Example fix

// before: single-shot start
if err := qqCh.Start(ctx); err != nil { return err }

// after: retry transient gateway-lookup failures with backoff
var err error
for attempt := 0; attempt < 3; attempt++ {
    if err = qqCh.Start(ctx); err == nil { break }
    if strings.Contains(err.Error(), "websocket info") { // transient path
        time.Sleep(time.Duration(attempt+1) * 2 * time.Second)
        continue
    }
    break
}
Defensive patterns

Strategy: retry

Validate before calling

// cheap connectivity gate before Start
if _, err := net.DialTimeout("tcp", "api.sgroup.qq.com:443", 3*time.Second); err != nil {
    return fmt.Errorf("QQ API unreachable, deferring channel start: %w", err)
}

Try / catch

// transient gateway lookups: bounded retry with backoff
var err error
for i := 0; i < 3; i++ {
    if err = ch.Start(ctx); err == nil || !strings.Contains(err.Error(), "websocket info") { break }
    select { case <-ctx.Done(): return ctx.Err(); case <-time.After(time.Duration(i+1) * 2 * time.Second): }
}

Prevention

When it happens

Trigger: Start() invoked with an invalid/expired access token (token source returned a token the WS endpoint rejects); network failure reaching the QQ open platform API; QQ API incident returning 5xx; sandbox environments without egress to the QQ domain.

Common situations: app_secret rotated so freshly minted tokens are for the wrong credentials; corporate proxies blocking WebSocket upgrade discovery; QQ open platform maintenance windows; intermittent DNS failures at startup causing repeated Start/Stop cycles.

Related errors


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