{"record":{"id":"8208c278c80ededa","repo":"chenhg5/cc-connect","slug":"cloud-web-websocket-disconnected","errorCode":null,"errorMessage":"cloud_web: websocket disconnected","messagePattern":"cloud_web: websocket disconnected","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"platform/cloud-web/ws.go","lineNumber":182,"sourceCode":"\tif err != nil {\n\t\t_ = conn.Close()\n\t\treturn err\n\t}\n\tt.setCaps(caps)\n\n\tt.mu.Lock()\n\tif t.conn != nil {\n\t\t_ = t.conn.Close()\n\t}\n\tt.conn = conn\n\tt.mu.Unlock()\n\n\tslog.Info(\"cloud_web: websocket connected\", \"url\", t.wsURL)\n\n\tconnected := true\n\tdefer func() {\n\t\tif connected && t.onDisconnected != nil {\n\t\t\tt.onDisconnected(fmt.Errorf(\"cloud_web: websocket disconnected\"))\n\t\t}\n\t}()\n\tif t.onConnected != nil {\n\t\tt.onConnected()\n\t}\n\n\tpingDone := make(chan struct{})\n\tgo func() {\n\t\tdefer close(pingDone)\n\t\tticker := time.NewTicker(wsPingInterval)\n\t\tdefer ticker.Stop()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-ticker.C:\n\t\t\t\tt.writeMu.Lock()\n\t\t\t\terr := conn.WriteControl(websocket.PingMessage, nil, time.Now().Add(5*time.Second))","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/cloud-web/ws.go#L164-L200","documentation":"This is not a thrown error but a synthetic error passed to the onDisconnected callback when the read/write loop of an established cloud-web WebSocket exits while the transport still considered itself connected. It notifies the engine that the previously healthy connection dropped so it can schedule a reconnect. The literal string carries no underlying cause — the real reason is whatever broke the loop.","triggerScenarios":"The connection read or write loop returns (read error, write error, server close frame, network drop) while `connected` is still true and t.onDisconnected is non-nil.","commonSituations":"Server restart or deploy dropping active sockets; idle connection reaped by a load balancer when ping/pong keepalive fails; network switch/VPN drop; mobile clients or flaky Wi-Fi interrupting long-lived connections.","solutions":["Let the existing connectLoop reconnect (this error is the signal that triggers it) — confirm reconnect/backoff is configured","Ensure ping/pong keepalive (wsPingPeriod/wsPongWait) is active so dead connections are detected and re-established","Investigate why the underlying connection died: server logs, LB idle timeout settings, network stability","Log the actual read-loop error alongside this callback so the drop cause isn't lost"],"exampleFix":"// before\nt.onDisconnected(fmt.Errorf(\"cloud_web: websocket disconnected\"))\n// after (preserve the real cause)\nt.onDisconnected(fmt.Errorf(\"cloud_web: websocket disconnected: %w\", readErr))","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Subscribe to onDisconnected and rely on connectLoop backoff\ntransport.OnDisconnected(func(err error) {\n    slog.Warn(\"cloud-web disconnected; reconnect scheduled\", \"err\", err)\n})","preventionTips":["Enable ping/pong keepalive so drops are detected and reconnected fast","Set load-balancer idle timeouts longer than the ping period","Handle onDisconnected by flushing/queuing pending sends","Monitor disconnect frequency to catch chronic network issues"],"tags":["websocket","reconnect","network","cloud-web"],"backgroundTag":"connection-lost","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}