chenhg5/cc-connect · critical

dial: %s

Error message

dial: %s

What it means

runWS dials the TuiTui websocket endpoint /robot/callback/ws with appID.appSecret auth; if the websocket handshake fails, the dialer error is wrapped as "dial: %s" after passing it through core.RedactToken to scrub the app secret from the message. This is the low-level connection error surfaced by connectLoop's reconnect cycle.

Source

Thrown at platform/tuitui/tuitui.go:329

		}
		slog.Warn("tuitui: websocket disconnected, retrying", "error", err, "backoff", backoff)
		select {
		case <-ctx.Done():
			return
		case <-time.After(backoff):
		}
		backoff *= 2
		if backoff > maxReconnectBackoff {
			backoff = maxReconnectBackoff
		}
	}
}

func (p *Platform) runWS(ctx context.Context) error {
	wsURL := p.wsBase + "/robot/callback/ws?auth=" + url.QueryEscape(p.appID+"."+p.appSecret)
	conn, _, err := websocket.DefaultDialer.DialContext(ctx, wsURL, nil)
	if err != nil {
		return fmt.Errorf("dial: %s", core.RedactToken(err.Error(), p.appSecret))
	}
	defer func() { _ = conn.Close() }()
	slog.Info("tuitui: websocket connected")

	done := make(chan error, 1)
	go func() {
		for {
			_, data, err := conn.ReadMessage()
			if err != nil {
				done <- err
				return
			}
			p.handleFrame(ctx, conn, data)
		}
	}()

	select {
	case <-ctx.Done():

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check network connectivity and whether the TuiTui endpoint is reachable (the redacted message will indicate DNS vs TLS vs HTTP failure).
  2. Verify wsBase and appID/appSecret in config — the auth query parameter embeds appID.appSecret and wrong values are rejected at handshake.
  3. Rely on connectLoop's retry/backoff for transient outages; investigate persistent failures in platform status or proxy settings.

Example fix

// before
wsBase = "https://wrong-host.example.com" // dial fails
// after
wsBase = "https://open.tuitui.example.com" // correct endpoint from platform docs
Defensive patterns

Strategy: retry

Validate before calling

// pre-check endpoint reachability
conn, err := net.DialTimeout("tcp", host, 5*time.Second)
if err != nil {
    log.Warn("tuitui endpoint unreachable", "err", err)
}

Try / catch

if err := p.Start(handler); err != nil {
    log.Error("tuitui start failed", "err", err) // dial errors surface via connectLoop logs
    // rely on connectLoop backoff; alert after N consecutive failures
}

Prevention

When it happens

Trigger: websocket.DefaultDialer.DialContext fails: server unreachable, DNS failure, TLS error, non-101 HTTP response (bad path/auth), or context cancellation mid-dial.

Common situations: TuiTui service outage or maintenance; corporate proxy/firewall blocking websocket upgrades; wrong wsBase URL configured; invalid appID/appSecret causing the server to reject the upgrade; network flaps triggering repeated reconnect dials.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/ea30641ee5cd04d6. Report an issue: GitHub.