{"record":{"id":"4020d0d4914a6f53","repo":"spacedriveapp/spacedrive","slug":"sync-request-timed-out-after-60s-peer-not-res","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/protocol/sync/transport.rs","lineNumber":202,"sourceCode":"\t\t\t\tanyhow::anyhow!(\"Failed to read response length: {}\", e)\n\t\t\t})?;\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":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/core/src/service/network/protocol/sync/transport.rs#L184-L220","documentation":"The tokio timeout(Duration::from_secs(60)) wrapping the entire response read elapsed. The peer accepted the connection and the request but did not deliver a complete response within 60 seconds - slow response generation on the peer, a stuck handler, or a stalled network path.","triggerScenarios":"Peer computing an expensive diff over a large library; peer handler deadlocked (for example lock contention); relay path with extreme latency; peer CPU saturated by another job.","commonSituations":"Initial sync of large libraries; low-power devices (phones, SBCs); peer busy with indexing or backups.","solutions":["Raise the timeout or make it adaptive to library size","Have the peer emit progress or keepalive bytes so the reader does not time out during long computations","Profile the peer handler stage that is slow","Retry once - transient stalls are common"],"exampleFix":"// before\nlet result = timeout(Duration::from_secs(60), async { /* read */ }).await;\n\n// after\nlet budget = Duration::from_secs(60 + (library_size / 10_000).max(0));\nlet result = timeout(budget, async { /* read */ }).await;","handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_sync_timeout(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"timed out after 60s\")\n}","tryCatchPattern":"match net.send_sync_request(device, request).await {\n    Ok(resp) => { /* ... */ }\n    Err(e) if is_sync_timeout(&e) => {\n        // peer alive but slow: retry with a longer budget before giving up\n        tokio::time::sleep(std::time::Duration::from_secs(5)).await;\n        net.send_sync_request(device, request).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Scale the timeout with library size instead of a fixed 60s","Have the peer send keepalive or progress bytes during long computations","Monitor peer CPU and lock contention when timeouts cluster"],"tags":["timeout","network","sync","iroh","rust"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}