{"record":{"id":"ba6a30ff9f855a15","repo":"spacedriveapp/spacedrive","slug":"path-is-not-local","errorCode":null,"errorMessage":"Path is not local","messagePattern":"Path is not local","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"core/src/ops/files/delete/strategy.rs","lineNumber":58,"sourceCode":"pub struct LocalDeleteStrategy;\n\n#[async_trait]\nimpl DeleteStrategy for LocalDeleteStrategy {\n\tasync fn execute(\n\t\t&self,\n\t\tctx: &JobContext<'_>,\n\t\tpaths: &[SdPath],\n\t\tmode: DeleteMode,\n\t) -> Result<Vec<DeleteResult>> {\n\t\tlet mut results = Vec::new();\n\n\t\tfor path in paths {\n\t\t\tlet result = match path {\n\t\t\t\t// Local physical path - use direct filesystem (fast path)\n\t\t\t\t_ if path.is_local() => {\n\t\t\t\t\tlet local_path = path\n\t\t\t\t\t\t.as_local_path()\n\t\t\t\t\t\t.ok_or_else(|| anyhow::anyhow!(\"Path is not local\"))?;\n\n\t\t\t\t\tlet size = self.get_path_size(local_path).await.unwrap_or(0);\n\n\t\t\t\t\tlet deletion_result = match mode {\n\t\t\t\t\t\tDeleteMode::Trash => self.move_to_trash(local_path).await,\n\t\t\t\t\t\tDeleteMode::Permanent => self.permanent_delete(local_path).await,\n\t\t\t\t\t\tDeleteMode::Secure => self.secure_delete(local_path).await,\n\t\t\t\t\t};\n\n\t\t\t\t\tDeleteResult {\n\t\t\t\t\t\tpath: path.clone(),\n\t\t\t\t\t\tsuccess: deletion_result.is_ok(),\n\t\t\t\t\t\tbytes_freed: if deletion_result.is_ok() { size } else { 0 },\n\t\t\t\t\t\terror: deletion_result.err().map(|e| e.to_string()),\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Cloud path - use VolumeBackend","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/core/src/ops/files/delete/strategy.rs#L40-L76","documentation":"Unreachable through normal data: the match arm is guarded by path.is_local() yet path.as_local_path() returned None immediately after. The two accessors disagree, which can only happen when an SdPath was constructed inconsistently - its kind claims local but it carries no usable local path. Treat it as an invariant violation or data-construction bug, not an environmental condition.","triggerScenarios":"Hand-constructed SdPath values with a local kind but missing path data; serialization round-trips dropping the local path component; a new SdPath variant where is_local() is true by kind but as_local_path() has no arm covering it.","commonSituations":"Code building SdPath from raw parts (importers, tests, migrations); deserializing older persisted path records into newer structures.","solutions":["Log the full SdPath value at the failure site to identify which construction produced it","Replace the is_local() and as_local_path() pair with a single as_local_path() check","Repair or regenerate persisted path records that deserialize into inconsistent values","Add a property test asserting is_local() implies as_local_path().is_some()"],"exampleFix":"// before\n_ if path.is_local() => {\n    let local_path = path\n        .as_local_path()\n        .ok_or_else(|| anyhow::anyhow!(\"Path is not local\"))?;\n    // ...\n}\n\n// after - one authoritative accessor, no invariant to violate\nif let Some(local_path) = path.as_local_path() {\n    let size = self.get_path_size(local_path).await.unwrap_or(0);\n    // ...\n} else {\n    // route to the remote or volume-backed strategy\n}","handlingStrategy":"type-guard","validationCode":"// Detect the inconsistency before enqueueing a delete job.\nif path.is_local() != path.as_local_path().is_some() {\n    anyhow::bail!(\n        \"inconsistent SdPath: is_local() and as_local_path() disagree for {:?}\",\n        path\n    );\n}","typeGuard":"// Authoritative narrowing: as_local_path() is the single source of truth.\nfn as_local(p: &SdPath) -> Option<&std::path::Path> {\n    p.as_local_path()\n}\n\nmatch as_local(path) {\n    Some(local) => { /* local delete fast path */ }\n    None => { /* remote or volume-backed path */ }\n}","tryCatchPattern":null,"preventionTips":["Construct SdPath only through its provided constructors","Never set the local kind without the local path payload","Round-trip test serialized paths after schema changes"],"tags":["filesystem","invariant","sdpath","delete"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}