jdx/mise · error
remote cache path must be relative
Error message
remote cache path must be relative
What it means
validate_cache_path rejects cache paths that are empty or absolute. Remote cache entry paths (manifest roots, archive entries, tree nodes) must be relative so they can be safely joined under a local output directory. Absolute paths would escape the artifact directory when materialized.
Solutions
- Regenerate the cache archive/manifest so all paths are relative to the output root (strip leading '/' and mount prefixes).
- Re-run the task to republish a clean entry rather than reusing the offending archive.
- If building archives yourself, use relative paths: tar -C <outdir> . instead of tar <abs-path>.
- Reject/inspect the remote entry at ingestion before it enters the cache.
Example fix
// before (creating archive) $ tar -czf out.tar.zst /home/me/project/dist // after $ cd /home/me/project && tar -czf out.tar.zst dist
Defensive patterns
Strategy: validation
Validate before calling
fn is_safe_relative(p: &Path) -> bool {
!p.as_os_str().is_empty() && !p.is_absolute()
} Type guard
fn is_valid_cache_path(p: &std::path::Path) -> bool {
use std::path::Component::*;
!p.as_os_str().is_empty()
&& !p.is_absolute()
&& p.components().all(|c| matches!(c, Normal(_)))
} Try / catch
match validate_cache_path(&entry_path) {
Ok(()) => {},
Err(e) if e.to_string().contains("must be relative") => {
return Err(eyre!("cache archive {key} has absolute path {entry_path:?}; rebuild it"));
}
Err(e) => return Err(e),
} Prevention
- Build archives with tar -C <outdir> . so members are relative.
- Never hand-edit cache manifests or archives.
- Sanitize paths (strip leading '/') before uploading to the cache.
- Test archives on one platform before sharing cross-platform.
When it happens
Trigger: get() validating manifest roots, archive_to_cas() validating tar entry paths, or materialize_remote_tree() validating node paths when a path is empty or starts with '/' (or a Windows prefix) (task_cache_store.rs:503).
Common situations: A hand-crafted or third-party-written cache archive containing absolute paths (e.g. tar entries like /home/user/out); manifests edited manually; archives created with different tar tooling including absolute members.
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
- invalid remote cache path component
- remote cache path escapes its output root
- remote cache symlink target is unsafe
- remote cache symlink target must be relative
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/0b349b84eed475c4.
Report an issue: GitHub.
Appendix: source
Thrown at src/task/task_cache_store.rs:503
action: action_digest,
metadata: Some(metadata),
output_root,
version: 1,
})
.await
}
async fn remove(&self, _key: &str) -> Result<()> {
// Ordinary cache writers intentionally have no remote-delete authority.
Ok(())
}
fn touch(&self, _key: &str) {}
}
fn validate_cache_path(path: &Path) -> Result<()> {
if path.as_os_str().is_empty() || path.is_absolute() {
bail!("remote cache path must be relative");
}
if path.components().any(|component| {
matches!(
component,
Component::ParentDir | Component::RootDir | Component::Prefix(_)
)
}) {
bail!("remote cache path escapes its output root");
}
Ok(())
}
fn cache_name(path: &Path) -> Result<String> {
let name = path
.file_name()
.and_then(|name| name.to_str())
.ok_or_else(|| eyre!("remote cache paths must be valid UTF-8"))?;
if name.is_empty() || name == "." || name == ".." || name.contains(['/', '\0']) {View on GitHub (pinned to 533346cc37)