spacedriveapp/spacedrive · error · anyhow::Error

Destination must have a device slug for cross-device transfe

Error message

Destination must have a device slug for cross-device transfer

What it means

Cross-device push (core/src/ops/files/copy/strategy.rs:298) requires the destination SdPath to carry a device slug, because it must resolve which peer device receives the file. SdPath::device_slug() returns Some only for the Physical variant (core/src/domain/addressing.rs:538); Cloud, Content, and Sidecar variants return None and hit this error before the transfer starts. Note the very next step resolves that slug to a device UUID via Library::resolve_device_slug, so the slug must also belong to a device registered in the current library.

Source

Thrown at core/src/ops/files/copy/strategy.rs:298

				// Both remote - not supported yet (would require relay)
				// Default to Push for now
				debug!("Both source and destination are remote - defaulting to Push");
				TransferDirection::Push
			}
		}
	}

	/// Execute a PUSH operation (local -> remote)
	async fn execute_push<'a>(
		&self,
		ctx: &JobContext<'a>,
		source: &SdPath,
		destination: &SdPath,
		_verify_checksum: bool,
		progress_callback: Option<&ProgressCallback<'a>>,
	) -> Result<u64> {
		let dest_device_slug = destination.device_slug().ok_or_else(|| {
			anyhow::anyhow!("Destination must have a device slug for cross-device transfer")
		})?;

		let library = ctx.library();
		let dest_device_id = library
			.resolve_device_slug(dest_device_slug)
			.ok_or_else(|| anyhow::anyhow!(
				"Could not resolve destination device slug '{}' to UUID in library {}. Device may not be registered in this library.",
				dest_device_slug,
				library.id()
			))?;

		debug!(
			"RemoteTransferStrategy PUSH: {} -> device:{} ({})",
			source, dest_device_slug, dest_device_id
		);

		let networking = ctx
			.networking_service()

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Route by SdPath variant: only Physical destinations with a peer slug go to execute_push; Cloud/Content destinations need their own cloud upload/content-ingest path.
  2. Before dispatch, validate `matches!(destination, SdPath::Physical { .. }) && destination.device_slug().is_some()`.
  3. If the target device was expected to be a peer but the slug is missing, rebuild the destination as Physical { device_slug: <peer slug>, path } from library device records.

Example fix

// before
CrossDeviceCopyStrategy.execute(ctx, source, cloud_destination, true, cb).await

// after
let Some(slug) = destination.device_slug() else {
    anyhow::bail!("destination {} has no device; route cloud targets to the cloud uploader", destination.display());
};
CrossDeviceCopyStrategy.execute(ctx, source, destination, true, cb).await
Defensive patterns

Strategy: type-guard

Validate before calling

// only Physical destinations with a slug may enter the push path
if destination.device_slug().is_none() {
    anyhow::bail!("cross-device push requires a Physical destination with a device slug, got {}", destination.display());
}

Type guard

fn is_push_destination(dest: &SdPath) -> bool {
    matches!(dest, SdPath::Physical { .. }) && dest.device_slug().is_some()
}

Try / catch

// route by destination kind instead of failing the transfer
if !is_push_destination(destination) {
    return CloudCopyStrategy::upload(ctx, source, destination).await;
}
CrossDeviceCopyStrategy.execute(ctx, source, destination, verify, cb).await

Prevention

When it happens

Trigger: Invoking the cross-device copy strategy with a destination like Cloud {'s3://bucket/...'}, Content {'content://<uuid>'}, or a Sidecar path — none of which identify a target device.

Common situations: A copy router that treats 'not local' as 'cross-device' and passes cloud destinations to the push path; UI building destinations from display URIs of non-physical schemes; serialization drift where a Physical destination is decoded as Content.

Related errors


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