spacedriveapp/spacedrive · error · anyhow::Error
Failed to connect to device: {}
Error message
Failed to connect to device: {} What it means
execute_pull connects to the peer's iroh node with ALPN b"spacedrive/filetransfer/1" (strategy.rs:494-498). The connect fails when the node is unreachable (offline, NAT without relay, relay outage), when the peer refuses the ALPN due to an incompatible daemon version, or on timeout. The underlying iroh error string is appended for diagnosis.
Source
Thrown at core/src/ops/files/copy/strategy.rs:498
)
})?;
drop(registry);
let endpoint = networking_guard
.endpoint()
.ok_or_else(|| anyhow::anyhow!("Networking endpoint not available"))?;
ctx.log(format!(
"Opening PULL connection to node {} (device {})",
node_id, source_device_id
));
// Connect to remote device
let node_addr = iroh::EndpointAddr::new(node_id);
let connection = endpoint
.connect(node_addr, b"spacedrive/filetransfer/1")
.await
.map_err(|e| anyhow::anyhow!("Failed to connect to device: {}", e))?;
let (mut send_stream, mut recv_stream) = connection
.open_bi()
.await
.map_err(|e| anyhow::anyhow!("Failed to open bidirectional stream: {}", e))?;
// Send PullRequest
let transfer_id = uuid::Uuid::new_v4();
let current_device_id = crate::device::get_current_device_id();
// Normalize path separators to forward slashes for cross-platform transmission.
// The receiving device may use a different OS separator (Windows \ vs Unix /).
let normalized_source_path =
PathBuf::from(source_path.to_string_lossy().replace('\\', "/"));
let pull_request =
crate::service::network::protocol::file_transfer::FileTransferMessage::PullRequest {
transfer_id,
source_path: normalized_source_path,
requested_by: current_device_id,View on GitHub (pinned to 6dfeccf211)
Solutions
- Confirm the peer device is online and retry the copy
- Inspect the appended iroh error (timeout vs refused vs no route) to target the fix
- Check relay configuration and firewall rules on both endpoints
- Ensure both devices run daemon versions agreeing on the spacedrive/filetransfer/1 protocol
Defensive patterns
Strategy: retry
Validate before calling
let online = networking.device_registry().read().await.get_node_by_device(device_id).is_some();
if !online {
return Err(anyhow::anyhow!("peer {} not connected; connect() would fail", device_id));
} Try / catch
let mut last = None;
for attempt in 0..3 {
match endpoint.connect(iroh::EndpointAddr::new(node_id), alpn).await {
Ok(c) => return Ok(c),
Err(e) => { last = Some(e); tokio::time::sleep(Duration::from_secs(1 << attempt)).await; }
}
}
Err(anyhow::anyhow!("connect failed after retries: {:?}", last)) Prevention
- Confirm peer online status before initiating a PULL
- Retry connections with exponential backoff; many failures are transient
- Keep daemon versions aligned so the spacedrive/filetransfer/1 ALPN is always accepted
When it happens
Trigger: Peer went offline between the registry lookup and the connect attempt; firewall/NAT blocks both direct and relayed paths; ALPN refused because the peer runs an older/newer protocol version; relay infrastructure unreachable.
Common situations: Remote device asleep or powered off; cross-network transfers during relay downtime; mixed daemon versions during a rolling upgrade.
Related errors
- Failed to open bidirectional stream: {}
- Source must be a physical path for PULL operation
- Destination must be local path for PULL operation
- Could not resolve source device slug '{}' to UUID in library
- Could not find node_id for device {} (slug: {}). Device may
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/9b35a24da40720e4.
Report an issue: GitHub.