chenhg5/cc-connect · error
cloud_web: websocket not connected
Error message
cloud_web: websocket not connected
What it means
wsTransport.Send checks the current connection under a read lock; if t.conn is nil (no active WebSocket), it returns this error instead of attempting a write. Callers sending a message through the cloud-web transport while disconnected get this immediate failure rather than a blocked write.
Source
Thrown at platform/cloud-web/ws.go:272
if base.Type == "capabilities_changed" {
var ch wireCapabilitiesChanged
if err := json.Unmarshal(raw, &ch); err == nil && len(ch.Capabilities) > 0 {
t.setCaps(capabilitySet(ch.Capabilities))
}
}
default:
if t.onInbound != nil {
t.onInbound(raw)
}
}
}
func (t *wsTransport) Send(ctx context.Context, msg map[string]any) error {
t.mu.RLock()
conn := t.conn
t.mu.RUnlock()
if conn == nil {
return fmt.Errorf("cloud_web: websocket not connected")
}
t.writeMu.Lock()
defer t.writeMu.Unlock()
return conn.WriteJSON(msg)
}
func (t *wsTransport) waitPreviewAck(refID string, timeout time.Duration) (string, error) {
ch := make(chan string, 1)
t.previewMu.Lock()
t.previewRequests[refID] = ch
t.previewMu.Unlock()
defer func() {
t.previewMu.Lock()
delete(t.previewRequests, refID)
t.previewMu.Unlock()
}()
select {
case handle := <-ch:View on GitHub (pinned to 4000b2338a)
Solutions
- Retry after the transport reconnects — check connection state / wait for onConnected before sending
- Buffer or queue outbound messages while disconnected and flush on reconnect
- Check why the connection is down (see disconnect logs) and restore connectivity/server
- Avoid calling Send before Start/connect completes; gate sends on a connected flag
Example fix
// before
if err := t.Send(ctx, msg); err != nil { ... }
// after (retry with backoff while disconnected)
if err := t.Send(ctx, msg); err != nil && strings.Contains(err.Error(), "not connected") {
time.Sleep(retryDelay)
err = t.Send(ctx, msg)
} Defensive patterns
Strategy: retry
Validate before calling
// Guard before sending
func (t *wsTransport) CanSend() bool {
t.mu.RLock()
defer t.mu.RUnlock()
return t.conn != nil
} Try / catch
// Retry send after reconnect
if err := t.Send(ctx, msg); err != nil {
if strings.Contains(err.Error(), "not connected") {
<-t.Connected() // channel closed on reconnect
err = t.Send(ctx, msg)
}
} Prevention
- Gate sends on connection-established signal (onConnected)
- Queue outbound messages during outages and flush on reconnect
- Don't call Send between Stop() and the next Start()
- Alert on 'not connected' rates to detect chronic disconnections
When it happens
Trigger: Send(ctx, msg) is invoked before connectLoop has established a connection, after a disconnect before reconnection completes, or during shutdown after the connection was cleared.
Common situations: Race between a message reply (e.g. streaming card update or preview) and a network drop; engine starts sending before the WebSocket handshake finishes; server outage with queued outbound messages; Stop() already called.
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
- cloud_web: ws_url or base_url is required for websocket tran
- cloud_web: send HTTP %d: %s
- cloud_web: parse register_ack: %w
- cloud_web: expected register_ack, got %q
- cloud_web: register rejected: %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/c10f1cdf9cd8376c.
Report an issue: GitHub.