spacedriveapp/spacedrive · error · anyhow::Error
Source must be a physical path for PULL operation
Error message
Source must be a physical path for PULL operation
What it means
execute_pull requires the source SdPath in physical form — a (device_slug, PathBuf) pair identifying a file on a specific remote device. as_physical() returns None when the source is a local or virtual/managed path with no device binding (strategy.rs:426-428), so the job cannot know which peer to pull from.
Source
Thrown at core/src/ops/files/copy/strategy.rs:428
error!("PUSH transfer failed: {}", e);
ctx.log(format!("PUSH transfer FAILED: {}", e));
Err(e)
}
}
}
/// Execute a PULL operation (remote -> local)
async fn execute_pull<'a>(
&self,
ctx: &JobContext<'a>,
source: &SdPath,
destination: &SdPath,
verify_checksum: bool,
progress_callback: Option<&ProgressCallback<'a>>,
) -> Result<u64> {
let (source_device_slug, source_path) = source
.as_physical()
.ok_or_else(|| anyhow::anyhow!("Source must be a physical path for PULL operation"))?;
let local_dest_path = destination
.as_local_path()
.ok_or_else(|| anyhow::anyhow!("Destination must be local path for PULL operation"))?;
let library = ctx.library();
let source_device_id = library
.resolve_device_slug(source_device_slug)
.ok_or_else(|| anyhow::anyhow!(
"Could not resolve source device slug '{}' to UUID in library {}. Device may not be registered in this library.",
source_device_slug,
library.id()
))?;
debug!(
"RemoteTransferStrategy PULL: device:{} ({}) -> {}",
source_device_slug,
source_device_id,View on GitHub (pinned to 6dfeccf211)
Solutions
- Represent the source as a physical path bound to the remote device's slug
- If the source is local, use the local copy strategy instead of remote PULL
- Fix direction determination so local sources never reach execute_pull
- Validate source.as_physical().is_some() before dispatching the job
Example fix
// before
let source = SdPath::local(PathBuf::from("/mnt/data/a.jpg")); // no device binding
remote_strategy.execute_pull(ctx, &source, &dest).await?; // "Source must be a physical path for PULL operation"
// after
let source = SdPath::physical("nas", PathBuf::from("/export/a.jpg"));
remote_strategy.execute_pull(ctx, &source, &dest).await?; Defensive patterns
Strategy: type-guard
Validate before calling
if source.as_physical().is_none() {
return Err(anyhow::anyhow!("PULL requires a physical (device-scoped) source; got {}", source));
} Type guard
fn is_physical_source(source: &SdPath) -> bool {
source.as_physical().is_some()
} Prevention
- Bind remote sources to a device slug via SdPath::physical before pulling
- Route local-to-local copies to the local strategy
- Check as_physical() during path construction, not inside the strategy
When it happens
Trigger: PULL issued with a source constructed as a local path; source is a virtual library location without device binding; RemoteTransferStrategy invoked directly for what is actually a local-to-local copy.
Common situations: Custom job code that always uses the remote strategy; SdPath built from a local location record; wrong direction chosen when both paths are local.
Related errors
- Destination must be local path for PULL operation
- Source must be local path for PUSH operation
- Could not resolve source device slug '{}' to UUID in library
- Could not resolve destination device slug '{}' to UUID in li
- Failed to connect to device: {}
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/739b651b6308f5ce.
Report an issue: GitHub.