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

  1. Represent the source as a physical path bound to the remote device's slug
  2. If the source is local, use the local copy strategy instead of remote PULL
  3. Fix direction determination so local sources never reach execute_pull
  4. 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

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


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