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
- 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.
- Before dispatch, validate `matches!(destination, SdPath::Physical { .. }) && destination.device_slug().is_some()`.
- 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
- Distinguish 'non-local Physical' (cross-device push) from 'Cloud/Content' (cloud writer) in the router — do not lump them together.
- Verify the slug resolves via Library::resolve_device_slug before starting the push.
- Build destinations for peers from library device records, never from display strings.
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
- Source path is not local
- Destination path is not local
- Source must be local path for PUSH operation
- Source must be a physical path for PULL operation
- Destination must be local path for PULL operation
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/afea1d6026c161d8.
Report an issue: GitHub.