spacedriveapp/spacedrive · warning · anyhow::Error

Device {} not found in registry (not paired or offline)

Error message

Device {} not found in registry (not paired or offline)

What it means

get_node_id_for_device(target_device) on the DeviceRegistry returned None in send_sync_message. The registry maps paired device UUIDs to iroh NodeIds; absence means the device was never paired, has been unpaired, or its entry lacks a recorded NodeId (for example a pairing created before node-id capture existed).

Source

Thrown at core/src/service/network/transports/sync.rs:40

#[async_trait::async_trait]
impl NetworkTransport for NetworkingService {
	/// Send a sync message to a target device
	///
	/// # Implementation Details
	///
	/// 1. Look up NodeId for device UUID via DeviceRegistry
	/// 2. Serialize the SyncMessage to JSON bytes
	/// 3. Send via Iroh endpoint using the sync protocol ALPN
	/// 4. Handle errors gracefully (device may be offline)
	async fn send_sync_message(&self, target_device: Uuid, message: SyncMessage) -> Result<()> {
		// 1. Look up NodeId for device UUID via public getter
		let device_registry_arc = self.device_registry();
		let node_id = {
			let registry = device_registry_arc.read().await;
			registry
				.get_node_id_for_device(target_device)
				.ok_or_else(|| {
					anyhow::anyhow!(
						"Device {} not found in registry (not paired or offline)",
						target_device
					)
				})?
		};

		tracing::info!(
			"Sending sync message to device {} (node {}), type: {:?}, library: {}",
			target_device,
			node_id,
			std::mem::discriminant(&message),
			message.library_id()
		);

		// 2. Serialize message to bytes
		let bytes = serde_json::to_vec(&message)
			.map_err(|e| anyhow::anyhow!("Failed to serialize sync message: {}", e))?;

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Verify the UUID is the paired device's UUID, not a library or instance id
  2. Re-pair the device so the registry records its current NodeId
  3. Backfill NodeIds for legacy pairing entries via a migration
  4. Restrict sync target selection in UI/CLI to paired devices

Example fix

// before
net.send_sync_message(device_id, msg).await?;

// after
let known = net.device_registry().read().await
    .get_node_id_for_device(device_id)
    .is_some();
if !known {
    tracing::warn!(device = %device_id, "skip sync: device not paired");
    return Ok(());
}
net.send_sync_message(device_id, msg).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Run before sending
let registry = net.device_registry().read().await;
if registry.get_node_id_for_device(target_device).is_none() {
    // not paired: skip, or prompt the user to pair
    return Ok(());
}
drop(registry);
net.send_sync_message(target_device, message).await?;

Type guard

fn is_device_not_in_registry(err: &anyhow::Error) -> bool {
    err.to_string().contains("not found in registry")
}

Try / catch

if let Err(e) = net.send_sync_message(device, msg).await {
    if is_device_not_in_registry(&e) {
        // expected state: mark unpaired and stop syncing to it; do not retry
        remove_from_sync_targets(device);
        return Ok(());
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Sending to an unpaired device UUID; passing a library or instance identifier where a device UUID is expected; device unpaired concurrently with the send; legacy pairing rows with no NodeId.

Common situations: After reinstalling or resetting a device identity; migrations that drop node-id data; frontend confusion between identifier kinds.

Related errors


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