{"record":{"id":"003ce1cec015190e","repo":"spacedriveapp/spacedrive","slug":"sync-request-timed-out-after-60s-peer-not-res-003ce1","errorCode":null,"errorMessage":"Sync request timed out after 60s - peer {} not responding","messagePattern":"Sync request timed out after 60s - peer (.+?) not responding","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"core/src/service/network/transports/sync.rs","lineNumber":299,"sourceCode":"\t\t\t\t.await\n\t\t\t\t.map_err(|e| anyhow::anyhow!(\"Failed to read response length: {}\", e))?;\n\t\t\tlet resp_len = u32::from_be_bytes(len_buf) as usize;\n\n\t\t\tdebug!(\"Receiving sync response of {} bytes\", resp_len);\n\n\t\t\tlet mut resp_buf = vec![0u8; resp_len];\n\t\t\trecv.read_exact(&mut resp_buf)\n\t\t\t\t.await\n\t\t\t\t.map_err(|e| anyhow::anyhow!(\"Failed to read response: {}\", e))?;\n\t\t\tOk::<_, anyhow::Error>(resp_buf)\n\t\t})\n\t\t.await;\n\n\t\tlet resp_buf = match result {\n\t\t\tOk(Ok(buf)) => buf,\n\t\t\tOk(Err(e)) => return Err(e),\n\t\t\tErr(_) => {\n\t\t\t\treturn Err(anyhow::anyhow!(\n\t\t\t\t\t\"Sync request timed out after 60s - peer {} not responding\",\n\t\t\t\t\ttarget_device\n\t\t\t\t))\n\t\t\t}\n\t\t};\n\n\t\t// Deserialize response\n\t\tlet response: SyncMessage = serde_json::from_slice(&resp_buf)\n\t\t\t.map_err(|e| anyhow::anyhow!(\"Failed to deserialize sync response: {}\", e))?;\n\n\t\tdebug!(\n\t\t\tdevice_uuid = %target_device,\n\t\t\tresponse_type = ?std::mem::discriminant(&response),\n\t\t\t\"Received sync response\"\n\t\t);\n\n\t\tOk(response)\n\t}","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/core/src/service/network/transports/sync.rs#L281-L317","documentation":"The 60-second tokio timeout wrapping the response read expired: the peer neither sent a response nor closed the stream. The transport connection is fine, but the peer's sync handler is stuck (blocked on a lock or a very long database operation) or traffic is black-holed by a NAT or relay path. Note the timeout wraps the whole read, so a very slow large response also trips it.","triggerScenarios":"Peer handler deadlocks on a contended lock while processing the request; initial sync of a huge dataset where the peer needs more than 60s to assemble the response; a relay or NAT path silently dropping packets so no data or FIN ever arrives.","commonSituations":"First sync after pairing two large libraries; peers on mobile or unstable networks; a peer suspended by the OS while holding the sync handler.","solutions":["Check peer health and its logs: a silently unresponsive peer is usually stuck, not slow","Retry with backoff; a second consecutive timeout on an idle peer confirms it is unavailable","For bulk sync, raise the timeout or move to a streamed job protocol so progress is visible instead of one 60s-capped response","Keep individual request payloads small so responses complete well under the cap"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Check peer responsiveness before committing to a long exchange\nif !transport.is_device_reachable(target_device).await {\n    return Ok(None);\n}","typeGuard":null,"tryCatchPattern":"match transport.send_sync_request(target, request).await {\n    Err(e) if e.to_string().contains(\"timed out after 60s\") => {\n        // peer hung: back off, verify peer health, retry a bounded number of times\n    }\n    other => other,\n}","preventionTips":["Keep request payloads small so responses finish well under the 60s cap","Move bulk sync to a streamed or job-based protocol with visible progress","Track consecutive timeouts per peer and quarantine unresponsive peers"],"tags":["network","sync","timeout","hang"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}