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 := trueView on GitHub (pinned to 4000b2338a)
Solutions
- 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
- Check server logs for post-upgrade closes (auth failures, panics)
- Test connectivity through any corporate proxy/firewall — ensure WebSocket upgrade + persistent connection is allowed
- 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
- Tune wsPongWait to exceed worst-case server response time
- Keep ping/pong keepalive enabled to detect dead sockets quickly
- Verify server implements the register_ack handshake before upgrading clients
- Test through production proxies/firewalls, not just localhost
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
- wecom-ws: ack timeout
- cloud_web: websocket disconnected
- cloud_web: preview_ack timeout
- upload init: %w
- upload chunk %d: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/1c13118881e9065b.
Report an issue: GitHub.