spacedriveapp/spacedrive · error · anyhow::Error
Path is not local
Error message
Path is not local
What it means
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.
Source
Thrown at core/src/ops/files/delete/strategy.rs:58
pub struct LocalDeleteStrategy;
#[async_trait]
impl DeleteStrategy for LocalDeleteStrategy {
async fn execute(
&self,
ctx: &JobContext<'_>,
paths: &[SdPath],
mode: DeleteMode,
) -> Result<Vec<DeleteResult>> {
let mut results = Vec::new();
for path in paths {
let result = match path {
// Local physical path - use direct filesystem (fast path)
_ if path.is_local() => {
let local_path = path
.as_local_path()
.ok_or_else(|| anyhow::anyhow!("Path is not local"))?;
let size = self.get_path_size(local_path).await.unwrap_or(0);
let deletion_result = match mode {
DeleteMode::Trash => self.move_to_trash(local_path).await,
DeleteMode::Permanent => self.permanent_delete(local_path).await,
DeleteMode::Secure => self.secure_delete(local_path).await,
};
DeleteResult {
path: path.clone(),
success: deletion_result.is_ok(),
bytes_freed: if deletion_result.is_ok() { size } else { 0 },
error: deletion_result.err().map(|e| e.to_string()),
}
}
// Cloud path - use VolumeBackendView on GitHub (pinned to 6dfeccf211)
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()
Example fix
// before
_ if path.is_local() => {
let local_path = path
.as_local_path()
.ok_or_else(|| anyhow::anyhow!("Path is not local"))?;
// ...
}
// after - one authoritative accessor, no invariant to violate
if let Some(local_path) = path.as_local_path() {
let size = self.get_path_size(local_path).await.unwrap_or(0);
// ...
} else {
// route to the remote or volume-backed strategy
} Defensive patterns
Strategy: type-guard
Validate before calling
// Detect the inconsistency before enqueueing a delete job.
if path.is_local() != path.as_local_path().is_some() {
anyhow::bail!(
"inconsistent SdPath: is_local() and as_local_path() disagree for {:?}",
path
);
} Type guard
// Authoritative narrowing: as_local_path() is the single source of truth.
fn as_local(p: &SdPath) -> Option<&std::path::Path> {
p.as_local_path()
}
match as_local(path) {
Some(local) => { /* local delete fast path */ }
None => { /* remote or volume-backed path */ }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Code building SdPath from raw parts (importers, tests, migrations); deserializing older persisted path records into newer structures.
Related errors
- Non-local address not supported for indexing yet: {}
- Non-local path not supported yet
- Path does not exist: {}
- Path must be a directory: {}
- Could not determine binary directory
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/ba6a30ff9f855a15.
Report an issue: GitHub.