chenhg5/cc-connect · error

read register_ack: %w

Error message

read register_ack: %w

What it means

After the WebSocket dial succeeds, connectOnce waits for the first frame (the register_ack) via conn.ReadMessage with a read deadline set. If that read fails — connection closed, timeout, or network error — the connection is closed and this error wraps the underlying cause. It means the client never received the registration acknowledgment.

Source

Thrown at platform/cloud-web/ws.go:161

		return err
	}
	if err := conn.WriteMessage(websocket.TextMessage, reg); err != nil {
		_ = conn.Close()
		return err
	}

	if err := conn.SetReadDeadline(time.Now().Add(wsPongWait)); err != nil {
		_ = conn.Close()
		return err
	}
	conn.SetPongHandler(func(string) error {
		return conn.SetReadDeadline(time.Now().Add(wsPongWait))
	})

	_, raw, err := conn.ReadMessage()
	if err != nil {
		_ = conn.Close()
		return fmt.Errorf("read register_ack: %w", err)
	}
	caps, err := parseRegisterAck(raw)
	if err != nil {
		_ = conn.Close()
		return err
	}
	t.setCaps(caps)

	t.mu.Lock()
	if t.conn != nil {
		_ = t.conn.Close()
	}
	t.conn = conn
	t.mu.Unlock()

	slog.Info("cloud_web: websocket connected", "url", t.wsURL)

	connected := true

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Inspect the wrapped error: 'timeout' means increase wsPongWait or fix a slow/unresponsive server; 'closed' means check why the server drops the connection right after upgrade
  2. Check server logs for post-upgrade closes (auth failures, panics)
  3. Test connectivity through any corporate proxy/firewall — ensure WebSocket upgrade + persistent connection is allowed
  4. Verify the server actually implements the register_ack first-frame handshake

Example fix

// before (opaque diagnosis)
return fmt.Errorf("read register_ack: %w", err)
// after (distinguish timeout from close)
if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseAbnormalClosure) {
    return fmt.Errorf("read register_ack: server closed connection: %w", err)
}
return fmt.Errorf("read register_ack: %w", err)
Defensive patterns

Strategy: retry

Try / catch

// connectLoop-style retry with backoff; classify the wrapped cause
for attempt := 0; ; attempt++ {
    err := connectOnce(ctx)
    if err == nil { return nil }
    if strings.Contains(err.Error(), "read register_ack") {
        slog.Warn("cloud-web: no register_ack received; retrying", "attempt", attempt, "err", err)
    }
    select {
    case <-ctx.Done(): return ctx.Err()
    case <-time.After(backoff(attempt)):
    }
}

Prevention

When it happens

Trigger: conn.ReadMessage returns an error before a frame arrives: server closes the connection immediately, wsPongWait read deadline expires because the server never sends the ack, TLS/proxy terminates the connection, or network drops.

Common situations: Server accepts the TCP/WebSocket upgrade then crashes or rejects and closes without sending ack; slow or blocked network exceeding the read deadline; corporate proxy that permits the upgrade but kills the stream; server authentication middleware dropping unauthorized connections silently.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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