spacedriveapp/spacedrive · error · anyhow::Error
Failed to open stream: {}
Error message
Failed to open stream: {} What it means
conn.open_uni() failed on the connection used for sending. Because this path reuses cached connections checked with close_reason().is_none(), the typical cause is the connection dying after that liveness check (race), or the peer not accepting unidirectional streams for SYNC_ALPN.
Source
Thrown at core/src/service/network/transports/sync.rs:127
}
// Track outbound connection so we can receive incoming streams on it
if let Some(cmd_sender) = self.command_sender() {
use crate::service::network::core::event_loop::EventLoopCommand;
let _ = cmd_sender.send(EventLoopCommand::TrackOutboundConnection {
node_id,
conn: new_conn.clone(),
});
}
new_conn
};
// Open a unidirectional stream and send the message
let mut send = conn
.open_uni()
.await
.map_err(|e| anyhow::anyhow!("Failed to open stream: {}", e))?;
// Write length prefix (required by multiplexer)
let len = bytes.len() as u32;
send.write_all(&len.to_be_bytes())
.await
.map_err(|e| anyhow::anyhow!("Failed to write length prefix: {}", e))?;
// Write message bytes
send.write_all(&bytes).await.map_err(|e| {
warn!(
device_uuid = %target_device,
error = %e,
"Failed to write sync message to stream"
);
anyhow::anyhow!("Failed to write message: {}", e)
})?;
send.finish()View on GitHub (pinned to 6dfeccf211)
Solutions
- On failure, evict the cache entry and retry once with a fresh connection
- Treat open_uni errors on cached connections as a cache-invalidation signal
- Verify the peer accepts length-prefixed uni streams (the multiplexer depends on them)
Example fix
// before
let mut send = conn.open_uni().await
.map_err(|e| anyhow::anyhow!("Failed to open stream: {}", e))?;
// after
let mut send = match conn.open_uni().await {
Ok(s) => s,
Err(_) => {
active_connections.write().await.remove(&cache_key); // evict stale entry
let conn = endpoint.connect(node_id, SYNC_ALPN).await?;
conn.open_uni().await?
}
}; Defensive patterns
Strategy: retry
Validate before calling
// Shrink the race before using a cached connection
let conn = {
let connections = active_connections.read().await;
match connections.get(&cache_key) {
Some(c) if c.close_reason().is_none() => c.clone(),
_ => return reconnect_and_send(device, node_id, bytes).await,
}
}; Try / catch
match conn.open_uni().await {
Ok(send) => send,
Err(_) => {
// cached connection died after the liveness check: evict and reconnect once
active_connections.write().await.remove(&cache_key);
let conn = endpoint.connect(node_id, SYNC_ALPN).await?;
conn.open_uni().await?
}
} Prevention
- Evict cache entries on any open_uni or write failure
- Treat cached connections as optimistic; always keep a one-shot reconnect path
- Add idle timeouts to the cache so long-dead connections are not reused
When it happens
Trigger: Cached connection died between the liveness check and open_uni; peer idle-timeout; peer restarted with the same NodeId; peer accept loop stopped so uni streams are refused.
Common situations: Long-lived daemons holding stale cached connections; laptop sleep/wake invalidating connections underneath the cache.
Related errors
- Failed to open bidirectional stream: {}
- Failed to send length: {}
- Failed to send request: {}
- Failed to read response length: {}
- Failed to read response: {}
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/fadf2be504eb1394.
Report an issue: GitHub.