{"record":{"id":"1a6ce39488edde7a","repo":"chenhg5/cc-connect","slug":"cloud-web-preview-ack-timeout-1a6ce3","errorCode":null,"errorMessage":"cloud_web: preview_ack timeout","messagePattern":"cloud_web: preview_ack timeout","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/cloud-web/ws.go","lineNumber":293,"sourceCode":"\tdefer t.writeMu.Unlock()\n\treturn conn.WriteJSON(msg)\n}\n\nfunc (t *wsTransport) waitPreviewAck(refID string, timeout time.Duration) (string, error) {\n\tch := make(chan string, 1)\n\tt.previewMu.Lock()\n\tt.previewRequests[refID] = ch\n\tt.previewMu.Unlock()\n\tdefer func() {\n\t\tt.previewMu.Lock()\n\t\tdelete(t.previewRequests, refID)\n\t\tt.previewMu.Unlock()\n\t}()\n\tselect {\n\tcase handle := <-ch:\n\t\treturn handle, nil\n\tcase <-time.After(timeout):\n\t\treturn \"\", fmt.Errorf(\"cloud_web: preview_ack timeout\")\n\t}\n}\n\nfunc resolveWSURL(baseURL, wsURL string) string {\n\tif strings.TrimSpace(wsURL) != \"\" {\n\t\treturn wsURL\n\t}\n\tbase := strings.TrimRight(strings.TrimSpace(baseURL), \"/\")\n\tif base == \"\" {\n\t\treturn \"\"\n\t}\n\tif strings.HasPrefix(base, \"https://\") {\n\t\treturn \"wss://\" + strings.TrimPrefix(base, \"https://\") + defaultWSPath\n\t}\n\tif strings.HasPrefix(base, \"http://\") {\n\t\treturn \"ws://\" + strings.TrimPrefix(base, \"http://\") + defaultWSPath\n\t}\n\tif strings.Contains(base, \"://\") {","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/cloud-web/ws.go#L275-L311","documentation":"waitPreviewAck registers a handler for a preview_ack frame and waits on a channel with a fixed timeout; if no matching preview_ack arrives before the deadline, it returns this error and the caller gives up on obtaining the card handle. The cloud-web peer never confirmed the preview/card-creation request in time.","triggerScenarios":"The select on `<-ch` times out because the server never sent a preview_ack for the requested preview id within `timeout`: request lost, server busy, connection dropped mid-request, or the ack id doesn't match.","commonSituations":"Slow or overloaded cloud-web hub; connection died right after sending the preview request so the ack never arrives; server doesn't implement the preview_ack flow or mismatches the correlation id; timeout configured too aggressively for a high-latency network.","solutions":["Increase the preview_ack timeout if the network/server is slow","Check the connection was alive during the request — a disconnect will swallow the ack; reconnect and retry the preview","Verify the server sends preview_ack with the same correlation id the client registered","Add retry logic around preview card creation; surface the timeout to the user as a transient failure"],"exampleFix":"// before\nhandle, err := t.waitPreviewAck(ctx, id, 3*time.Second)\n// after (retry once on timeout)\nhandle, err := t.waitPreviewAck(ctx, id, 3*time.Second)\nif err != nil {\n    handle, err = t.waitPreviewAck(ctx, id, 10*time.Second)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Retry the preview request with backoff on timeout\nhandle, err := waitPreviewAck(ctx, id, timeout)\nif err != nil && strings.Contains(err.Error(), \"preview_ack timeout\") {\n    select {\n    case <-ctx.Done():\n    case <-time.After(backoff):\n        handle, err = waitPreviewAck(ctx, id, timeout*2)\n    }\n}","preventionTips":["Size the timeout for worst-case round-trip + server latency","Verify the server echoes the correlation id in preview_ack","Check connection liveness before issuing preview requests","Fall back to a non-preview card path when acks time out"],"tags":["websocket","timeout","ack","cloud-web"],"backgroundTag":"request-timeout","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"}