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

  1. Make the source a local path (download/materialize it first) before a PUSH copy
  2. If the file lives on the remote device, run the copy on that device or use PULL from the destination device
  3. Fix direction selection so both-remote raises 'not supported' instead of defaulting to Push
  4. 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

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


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