spacedriveapp/spacedrive · error · anyhow::Error
Source must be local path for PUSH operation
Error message
Source must be local path for PUSH operation
What it means
PUSH streams bytes from this machine to the peer, so the source must resolve to a local filesystem path. source.as_local_path() returns None when the SdPath is a device-scoped (physical) or otherwise non-local variant, leaving nothing local to read and stream (strategy.rs:319-321). Note the direction chooser defaults both-remote cases to Push (strategy.rs:280-283), which then fails here.
Source
Thrown at core/src/ops/files/copy/strategy.rs:321
.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()
.ok_or_else(|| anyhow::anyhow!("Networking service not available"))?;
let local_path = source
.as_local_path()
.ok_or_else(|| anyhow::anyhow!("Source must be local path for PUSH operation"))?;
let metadata = tokio::fs::metadata(local_path).await?;
let file_size = metadata.len();
let checksum = calculate_file_checksum(local_path)
.await
.map(Some)
.map_err(|e| anyhow::anyhow!("Failed to calculate checksum: {}", e))?;
info!(
"Initiating PUSH transfer: {} ({} bytes) -> device:{} ({})",
local_path.display(),
file_size,
dest_device_slug,
dest_device_id
);
ctx.log(format!(View on GitHub (pinned to 6dfeccf211)
Solutions
- Make the source a local path (download/materialize it first) before a PUSH copy
- If the file lives on the remote device, run the copy on that device or use PULL from the destination device
- Fix direction selection so both-remote raises 'not supported' instead of defaulting to Push
- Validate source.as_local_path().is_some() before dispatching to the remote strategy
Example fix
// before
// source = SdPath::physical("nas", "/data/a.jpg")
remote_strategy.execute_push(ctx, &source, &dest).await?; // "Source must be local path for PUSH operation"
// after
match source.as_local_path() {
Some(_local) => remote_strategy.execute_push(ctx, &source, &dest).await,
None => Err(anyhow::anyhow!("source {} is remote; PULL it from the owning device instead", source)),
} Defensive patterns
Strategy: type-guard
Validate before calling
if source.as_local_path().is_none() {
return Err(anyhow::anyhow!("PUSH requires a local source; got {}", source));
} Type guard
fn is_local_source(source: &SdPath) -> bool {
source.as_local_path().is_some()
} Prevention
- Narrow on SdPath variant (as_local_path/as_physical) before choosing PUSH vs PULL
- Reject both-remote copies explicitly instead of relying on the Push default
- Build source paths with SdPath::local when the file is on this machine
When it happens
Trigger: PUSH invoked with a source bound to a remote device slug; both source and destination remote so determine_direction falls through to Push over an unsupported case; source SdPath constructed via a physical/virtual form instead of a local path.
Common situations: Custom job code calling RemoteTransferStrategy directly; both-remote copy attempted from a third machine; source built with SdPath::physical while the file is actually local.
Related errors
- Could not resolve destination device slug '{}' to UUID in li
- Source must be a physical path for PULL operation
- Destination must be local path for PULL operation
- Networking service not available
- Could not resolve source device slug '{}' to UUID in library
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/2e7c4ea73d718c70.
Report an issue: GitHub.