{"record":{"id":"88c401ef856e43d7","repo":"spacedriveapp/spacedrive","slug":"destination-must-be-local-path-for-pull-operation","errorCode":null,"errorMessage":"Destination must be local path for PULL operation","messagePattern":"Destination must be local path for PULL operation","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"core/src/ops/files/copy/strategy.rs","lineNumber":432,"sourceCode":"\t\t}\n\t}\n\n\t/// Execute a PULL operation (remote -> local)\n\tasync fn execute_pull<'a>(\n\t\t&self,\n\t\tctx: &JobContext<'a>,\n\t\tsource: &SdPath,\n\t\tdestination: &SdPath,\n\t\tverify_checksum: bool,\n\t\tprogress_callback: Option<&ProgressCallback<'a>>,\n\t) -> Result<u64> {\n\t\tlet (source_device_slug, source_path) = source\n\t\t\t.as_physical()\n\t\t\t.ok_or_else(|| anyhow::anyhow!(\"Source must be a physical path for PULL operation\"))?;\n\n\t\tlet local_dest_path = destination\n\t\t\t.as_local_path()\n\t\t\t.ok_or_else(|| anyhow::anyhow!(\"Destination must be local path for PULL operation\"))?;\n\n\t\tlet library = ctx.library();\n\t\tlet source_device_id = library\n\t\t\t.resolve_device_slug(source_device_slug)\n\t\t\t.ok_or_else(|| anyhow::anyhow!(\n\t\t\t\t\"Could not resolve source device slug '{}' to UUID in library {}. Device may not be registered in this library.\",\n\t\t\t\tsource_device_slug,\n\t\t\t\tlibrary.id()\n\t\t\t))?;\n\n\t\tdebug!(\n\t\t\t\"RemoteTransferStrategy PULL: device:{} ({}) -> {}\",\n\t\t\tsource_device_slug,\n\t\t\tsource_device_id,\n\t\t\tlocal_dest_path.display()\n\t\t);\n\n\t\tinfo!(","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/core/src/ops/files/copy/strategy.rs#L414-L450","documentation":"PULL writes incoming bytes to the local filesystem, so destination.as_local_path() must yield a real PathBuf (strategy.rs:430-432). None means the destination SdPath is device-scoped or virtual; there is no local target path at which the downloaded file can be created.","triggerScenarios":"Pulling to a destination that lives on another device (device-scoped SdPath); destination built from a virtual library location with no local materialization; both-remote copy attempted from the wrong machine.","commonSituations":"User drops a file onto a folder that resides on a different device; job executed on a third machine that owns neither endpoint.","solutions":["Make the destination a local path on the machine running the job","Run the PULL on the machine that owns the destination location","Guard destination.as_local_path().is_some() before starting the job","For both-remote copies, chain two hops (pull here, then push) or execute on one of the endpoints"],"exampleFix":"// before\nlet dest = SdPath::physical(\"laptop-b\", PathBuf::from(\"photos/a.jpg\"));\nremote_strategy.execute_pull(ctx, &src, &dest).await?; // \"Destination must be local path for PULL operation\"\n\n// after\nlet dest = SdPath::local(PathBuf::from(\"/home/me/photos/a.jpg\"));\nremote_strategy.execute_pull(ctx, &src, &dest).await?;","handlingStrategy":"type-guard","validationCode":"if destination.as_local_path().is_none() {\n    return Err(anyhow::anyhow!(\"PULL requires a local destination; got {}\", destination));\n}","typeGuard":"fn is_local_destination(destination: &SdPath) -> bool {\n    destination.as_local_path().is_some()\n}","tryCatchPattern":null,"preventionTips":["Materialize destinations to local paths before starting a PULL","Run the pull job on the machine that owns the destination location","Reject remote destinations early in the job input validation layer"],"tags":["rust","spacedrive","pull","sd-path","cross-device","copy"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}