{"record":{"id":"a5992a4dc2326ceb","repo":"spacedriveapp/spacedrive","slug":"connection-closed-without-response","errorCode":null,"errorMessage":"Connection closed without response","messagePattern":"Connection closed without response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/ts-client/src/transport.ts","lineNumber":362,"sourceCode":"\t\tconst requestLine = JSON.stringify(request) + \"\\n\";\n\t\tawait socket.write(requestLine);\n\n\t\t// Read response\n\t\tconst reader = socket.reader;\n\t\tlet buffer = \"\";\n\n\t\tfor await (const chunk of reader) {\n\t\t\tbuffer += new TextDecoder().decode(chunk);\n\n\t\t\tconst newlineIndex = buffer.indexOf(\"\\n\");\n\t\t\tif (newlineIndex !== -1) {\n\t\t\t\tconst line = buffer.slice(0, newlineIndex).trim();\n\t\t\t\tsocket.end();\n\t\t\t\treturn JSON.parse(line);\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(\"Connection closed without response\");\n\t}\n\n\tasync subscribe(\n\t\tcallback: (event: any) => void,\n\t\toptions?: SubscriptionOptions,\n\t): Promise<() => void> {\n\t\t// @ts-ignore - Bun global\n\t\tconst socket = await Bun.connect({\n\t\t\tunix: this.socketPath,\n\t\t});\n\n\t\t// Subscribe to relevant events (excludes spammy LogMessage/JobProgress)\n\t\tconst subscribeRequest = {\n\t\t\tSubscribe: {\n\t\t\t\tevent_types: options?.event_types ?? DEFAULT_EVENT_SUBSCRIPTION,\n\t\t\t\tfilter: options?.filter ?? null,\n\t\t\t},\n\t\t};","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/packages/ts-client/src/transport.ts#L344-L380","documentation":"Returned by FileSyncService::sync_now when the in-memory active_syncs map (Arc<RwLock<HashMap>>) already contains conduit_id, meaning another sync for the same conduit is currently running. This is a client-side concurrency guard, not a DB constraint — the map is populated when a sync starts and cleaned up when it finishes.","triggerScenarios":"Invoking sync_now for the same conduit twice before the first run completes: double-trigger from UI, a scheduler tick colliding with a manual sync, or a retry fired while the original request is still executing.","commonSituations":"Impatient double-click on 'Sync now'; overlapping cron/schedule and manual trigger; long-running first sync (large tree) during which a second request arrives.","solutions":["Wait for the in-flight sync to finish (poll its SyncHandle / job status) instead of issuing a second sync_now.","Debounce the trigger in the client so concurrent calls coalesce into one.","If the map is stuck due to a panicked sync task, restart the daemon to clear active_syncs."],"exampleFix":"// before\nlet handle = sync_svc.sync_now(conduit_id).await?; // second call errors\n\n// after\nlet handle = match sync_svc.sync_now(conduit_id).await {\n    Ok(h) => h,\n    Err(e) if e.to_string().contains(\"already in progress\") => {\n        return Ok(()); // a sync is already running; nothing to do\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Coalesce duplicate triggers: in-progress is not a failure.\nmatch svc.sync_now(id).await {\n    Ok(h) => Ok(Some(h)),\n    Err(e) if e.to_string().contains(\"already in progress\") => Ok(None),\n    Err(e) => Err(e),\n}","preventionTips":["Debounce 'Sync now' buttons and coalesce scheduler/manual triggers per conduit.","Track the returned SyncHandle and wait for completion before allowing a new trigger.","If active_syncs never drains (stuck task), restart the daemon to clear the map."],"tags":["rust","file-sync","concurrency","rate-limiting"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}