jdx/mise · error
remote cache path must be relative
Error message
remote cache path must be relative
What it means
mise's remote task cache rejects cache entry paths that are empty or absolute before storing or materializing them. Remote cache paths are always interpreted relative to a per-task output root, so an absolute path would break the digest-addressed store and could write outside it. validate_cache_path runs before get, archive_to_cas, and materialize_remote_tree.
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 afd2eddd3a)
Solutions
- Make the path relative to the task's output root before passing it to the cache API.
- Check for a task definition where a cached output is specified as an absolute path and change it to a relative path.
- If you have an absolute path programmatically, strip the output root prefix (path.strip_prefix(root)?) before caching.
Example fix
// before
store.get(Path::new("/abs/build/out.bin"), &key).await?;
// after
let rel = Path::new("/abs/build/out.bin").strip_prefix("/abs/build")?;
store.get(rel, &key).await?; Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_cache_path(p: &Path) -> bool {
!p.as_os_str().is_empty() && !p.is_absolute()
}
// call: assert!(is_valid_cache_path(&rel_path), "path must be relative"); Type guard
fn as_relative_cache_path(p: &Path) -> Option<&Path> {
(!p.as_os_str().is_empty() && !p.is_absolute()).then_some(p)
} Try / catch
match store.get(&rel, &key).await {
Err(e) if e.to_string().contains("remote cache path must be relative") => {
// fix path: strip the root prefix and retry
}
r => r?,
} Prevention
- Always pass paths relative to the task output root into the cache API
- Use Path::strip_prefix(root) instead of manual string slicing
- Add a debug assertion that cached paths are relative
When it happens
Trigger: Calling get, archive_to_cas (via commit), or materialize_remote_tree with a cache path that is empty (as_os_str().is_empty()) or absolute (Path::is_absolute, e.g. "/abs/out.bin" on Unix or "C:\\x" on Windows).
Common situations: Task [out] declarations or task configs that accidentally use an absolute path for a cached output; code that joins a root directory into the path before passing it to the cache API instead of passing the root-relative path.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- remote cache path escapes its output root
- invalid remote cache path component
- remote cache symlink target must be relative
- remote cache symlink target is unsafe
- invalid remote action manifest ETag
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/0b349b84eed475c4.
Report an issue: GitHub.