spacedriveapp/spacedrive · error · anyhow::Error

Failed to connect to {}: {}

Error message

Failed to connect to {}: {}

What it means

endpoint.connect(node_id.into(), SYNC_ALPN) failed inside send_sync_request. Iroh must resolve the peer NodeId to reachable addresses (discovery, relays, cached direct addresses) and complete a QUIC/TLS handshake for the sync ALPN; the appended text is the underlying iroh error. It means the peer was unreachable at the transport level, not that sync logic failed.

Source

Thrown at core/src/service/network/protocol/sync/transport.rs:153

			library_id = %request.library_id(),
			"Sending sync request"
		);

		// Get endpoint
		let endpoint = self
			.endpoint
			.as_ref()
			.ok_or_else(|| anyhow::anyhow!("Network endpoint not initialized"))?;

		// Connect with SYNC_ALPN
		let conn = endpoint.connect(node_id.into(), SYNC_ALPN).await.map_err(|e| {
			warn!(
				device_uuid = %target_device,
				node_id = %node_id,
				error = %e,
				"Failed to connect to device for sync request"
			);
			anyhow::anyhow!("Failed to connect to {}: {}", target_device, e)
		})?;

		// Open bidirectional stream
		let (mut send, mut recv) = conn
			.open_bi()
			.await
			.map_err(|e| anyhow::anyhow!("Failed to open bidirectional stream: {}", e))?;

		// Serialize and send request
		let req_bytes = serde_json::to_vec(&request)
			.map_err(|e| anyhow::anyhow!("Failed to serialize sync request: {}", e))?;

		let len = req_bytes.len() as u32;
		send.write_all(&len.to_be_bytes())
			.await
			.map_err(|e| anyhow::anyhow!("Failed to send length: {}", e))?;
		send.write_all(&req_bytes)
			.await

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Confirm the peer is online and paired (presence/heartbeat) before initiating sync
  2. Verify iroh relay and discovery configuration on both peers
  3. Retry with backoff - relay path establishment is often transient
  4. Re-pair the devices if the peer reset its identity (new NodeId)
  5. Ensure both devices run versions that agree on SYNC_ALPN

Example fix

// before
let resp = net.send_sync_request(device, req).await?;

// after
let resp = match net.send_sync_request(device, req.clone()).await {
    Ok(resp) => resp,
    Err(e) if is_connect_failure(&e) => {
        tokio::time::sleep(std::time::Duration::from_secs(2)).await;
        net.send_sync_request(device, req).await? // single retry
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: retry

Validate before calling

// Best-effort pre-check: skip peers not marked online
if !device_presence.is_online(device) {
    return Ok(None);
}
net.send_sync_request(device, request).await?;

Type guard

fn is_connect_failure(err: &anyhow::Error) -> bool {
    err.to_string().starts_with("Failed to connect to")
}

Try / catch

let mut attempt = 0;
loop {
    match net.send_sync_request(device, request.clone()).await {
        Ok(resp) => break Ok(resp),
        Err(e) if is_connect_failure(&e) && attempt < 2 => {
            attempt += 1;
            tokio::time::sleep(std::time::Duration::from_secs(2u64 * attempt)).await;
        }
        Err(e) if is_connect_failure(&e) => {
            mark_device_offline(device);
            break Err(e);
        }
        Err(e) => break Err(e),
    }
}

Prevention

When it happens

Trigger: Target device powered off or asleep; peer NodeId stale after an identity reset; no relay/discovery configured so the NodeId cannot be resolved to addresses; both peers behind restrictive NATs; ALPN mismatch because the peer runs a different spacedrive version.

Common situations: Syncing to a laptop that went to sleep; peer changed network leaving only stale address records; one device upgraded so SYNC_ALPN changed; air-gapped or relay-blocked networks.

Related errors


AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16). Data as JSON: /api/errors/7dd7261e861cc4b8. Report an issue: GitHub.