jdx/mise · error
invalid path inside recovery directory
Error message
invalid path inside recovery directory
What it means
When validating a Dir snapshot, every recorded relative path must be non-empty, contain only Normal components (no `..`, `.`, root, or prefix), and be unique. This bail means the snapshot's internal path list is malformed — empty, traversal-like, or duplicated. It guards against restoring files outside the recovery directory from corrupt or crafted journal data.
Source
Thrown at src/system/history/recovery.rs:169
read_blob(state_dir, content)?;
}
PathSnapshot::Dir {
files, links, dirs, ..
} => {
let mut seen = BTreeSet::new();
for relative in files
.iter()
.map(|f| &f.rel)
.chain(links.iter().map(|f| &f.rel))
.chain(dirs.iter().map(|f| &f.rel))
{
if relative.as_os_str().is_empty()
|| !relative
.components()
.all(|c| matches!(c, Component::Normal(_)))
|| !seen.insert(relative)
{
bail!("invalid path inside recovery directory");
}
}
for leaf in files
.iter()
.map(|f| &f.rel)
.chain(links.iter().map(|f| &f.rel))
{
if seen
.iter()
.any(|other| *other != leaf && other.starts_with(leaf))
{
bail!("recovery directory descends through a file or symlink");
}
}
for file in files {
read_blob(state_dir, &file.content)?;
}
}View on GitHub (pinned to afd2eddd3a)
Solutions
- Inspect the pending-operation JSON for the offending `rel` entry and correct it to a clean relative path like `sub/file.txt`.
- Discard the corrupt record and accept current contents; restore files manually from your dotfiles repository.
- Report as a bug if the state directory was never edited — capture should never produce such paths.
Example fix
// before (malicious/corrupt entry) "rel": "../../.ssh/authorized_keys" // after (clean relative path) "rel": "git/config"
Defensive patterns
Strategy: validation
Validate before calling
fn rel_is_safe(rel: &std::path::Path) -> bool {
!rel.as_os_str().is_empty()
&& rel.components().all(|c| matches!(c, std::path::Component::Normal(_)))
}
// check every rel entry in the snapshot before recovery Try / catch
match result { Err(e) if e.to_string().contains("invalid path inside recovery directory") => /* snapshot corrupt or tampered; discard record and restore manually */, other => other? } Prevention
- Never edit pending-operation JSON by hand
- Keep state directory writable only by the owning user
- Treat 'invalid path' errors as possible tampering; audit the journal before re-running
When it happens
Trigger: validate_snapshot -> PathSnapshot::Dir branch encounters a file/link/dir entry whose `rel` is empty, contains ParentDir/CurDir/root components, or duplicates an already-seen relative path.
Common situations: Hand-edited or corrupted pending-operation JSON, an injected/malicious journal, or a bug in snapshot capture producing duplicate or non-canonical relative paths.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- invalid recovery destination
- [dotfiles]."{}": target is not a safe OCI path
- brew-cask: invalid {kind} '{value}'
- brew-cask: staged symlink path escaped extraction root: {}
- brew-cask: refusing generic artifact source outside the extr
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/7245533563c3d2d7.
Report an issue: GitHub.