{"record":{"id":"accfb86a3e11f157","repo":"spacedriveapp/spacedrive","slug":"failed-to-open-bidirectional-stream-accfb8","errorCode":null,"errorMessage":"Failed to open bidirectional stream: {}","messagePattern":"Failed to open bidirectional stream: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"core/src/service/network/transports/sync.rs","lineNumber":257,"sourceCode":"\t\t\t}\n\n\t\t\t// Track it\n\t\t\tif let Some(cmd_sender) = self.command_sender() {\n\t\t\t\tuse crate::service::network::core::event_loop::EventLoopCommand;\n\t\t\t\tlet _ = cmd_sender.send(EventLoopCommand::TrackOutboundConnection {\n\t\t\t\t\tnode_id,\n\t\t\t\t\tconn: new_conn.clone(),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tnew_conn\n\t\t};\n\n\t\t// Open bidirectional stream\n\t\tlet (mut send, mut recv) = conn\n\t\t\t.open_bi()\n\t\t\t.await\n\t\t\t.map_err(|e| anyhow::anyhow!(\"Failed to open bidirectional stream: {}\", e))?;\n\n\t\t// Serialize and send request\n\t\tlet req_bytes = serde_json::to_vec(&request)\n\t\t\t.map_err(|e| anyhow::anyhow!(\"Failed to serialize sync request: {}\", e))?;\n\n\t\tlet len = req_bytes.len() as u32;\n\t\tsend.write_all(&len.to_be_bytes())\n\t\t\t.await\n\t\t\t.map_err(|e| anyhow::anyhow!(\"Failed to send length: {}\", e))?;\n\t\tsend.write_all(&req_bytes)\n\t\t\t.await\n\t\t\t.map_err(|e| anyhow::anyhow!(\"Failed to send request: {}\", e))?;\n\n\t\t// Properly close send stream\n\t\tsend.finish()\n\t\t\t.map_err(|e| anyhow::anyhow!(\"Failed to finish stream: {}\", e))?;\n\n\t\tdebug!(\"Sync request sent, waiting for response...\");","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/core/src/service/network/transports/sync.rs#L239-L275","documentation":"conn.open_bi() failed when opening the bidirectional QUIC stream that carries the length-prefixed sync exchange. The connection handle existed, usually pulled from the cache keyed by (node_id, SYNC_ALPN), but the underlying connection was already closed or lost, or the peer refused a new stream.","triggerScenarios":"Reusing a cached connection whose close_reason() was still None but that the peer closed a moment later (race between the cache check and open_bi); connection dropped by idle timeout; peer hit its concurrent bidirectional stream limit.","commonSituations":"Long-lived daemons with a warm connection cache; laptop peers sleeping and waking; mobile peers cycling networks.","solutions":["On this error, remove the cache_key from active_connections and retry once with a freshly connected endpoint.connect(...)","Re-check close_reason() immediately before open_bi and treat any Some(_) as a cache miss","Bound the retry to one attempt so a dead peer cannot cause a connect loop"],"exampleFix":"// before\nlet (mut send, mut recv) = conn.open_bi().await.map_err(|e| anyhow::anyhow!(\"Failed to open bidirectional stream: {}\", e))?;\n\n// after\nlet (mut send, mut recv) = match conn.open_bi().await {\n    Ok(pair) => pair,\n    Err(_) => {\n        active_connections.write().await.remove(&cache_key);\n        let conn = endpoint.connect(node_id, SYNC_ALPN).await?;\n        conn.open_bi().await?\n    }\n};","handlingStrategy":"retry","validationCode":"// Treat any closed cached connection as a cache miss before streaming\nlet usable = connections.get(&cache_key).is_some_and(|c| c.close_reason().is_none());\nif !usable {\n    active_connections.write().await.remove(&cache_key);\n}","typeGuard":null,"tryCatchPattern":"match conn.open_bi().await {\n    Err(_) => {\n        active_connections.write().await.remove(&cache_key);\n        let conn = endpoint.connect(node_id, SYNC_ALPN).await?;\n        conn.open_bi().await\n    }\n    ok => ok,\n}","preventionTips":["Always evict the cache entry when a stream or connection error occurs","Bound retries to one reconnect attempt per request","Re-check close_reason immediately before reusing a cached connection"],"tags":["network","sync","quic","connection-cache","stale-connection"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}