jdx/mise · error
invalid dependency sidecar path
Error message
invalid dependency sidecar path {} What it means
Dependency sidecars record an external dependency graph per tool. `GraphRef::resolve_path` validates the sidecar's relative `dir`: it must be relative, contain only normal path components, and have no backslashes — otherwise the path could escape the tool directory or be non-portable. It then resolves the dir against the lockfile's parent directory.
Solutions
- Fix the `path` in the lockfile's dependency sidecar entry to a relative path with only normal components (e.g. `deps/tool`)
- Remove any `..`, absolute prefixes, or `\` separators from the path
- Regenerate the lockfile instead of hand-editing so the sidecar path is produced correctly
- If the graph lives elsewhere, move the sidecar directory under the tool directory and reference it relatively
Example fix
# before (mise.lock) path = "../shared/graph.toml" # after path = "shared/graph.toml"
Defensive patterns
Strategy: validation
Validate before calling
use std::path::{Component, Path};
fn is_valid_sidecar_dir(dir: &Path) -> bool {
!dir.is_absolute()
&& dir.components().all(|c| matches!(c, Component::Normal(_)))
&& !dir.to_string_lossy().contains('\\')
} Type guard
fn valid_sidecar_dir(dir: &str) -> Option<&str> {
let p = Path::new(dir);
(!p.is_absolute()
&& p.components().all(|c| matches!(c, Component::Normal(_)))
&& !dir.contains('\\')).then_some(dir)
} Prevention
- Never hand-edit sidecar paths in mise.lock; regenerate instead
- Keep sidecar directories relative to the lockfile location
- Normalize Windows-produced paths to forward slashes before committing
- Reject `..` components when generating sidecar paths in scripts
When it happens
Trigger: Loading a lockfile whose `[dependency]` sidecar entry has an absolute path, `..`/root/curdir components (e.g. `../shared/deps`), or Windows-style backslashes in `path`, then calling `resolve_path`.
Common situations: Hand-edited or generated-by-script lockfiles with absolute or traversal paths; lockfiles copied from Windows; tools writing sidecar paths computed on another OS.
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
- aube lockfile must contain a mapping
- bootstrap_command returned an unsafe mise path
- brew-cask: command_wrapper requires a command name without…
- {error}
- install_mise must be an absolute path or start with ~/
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/5c98a22c79d7f3bb.
Report an issue: GitHub.
Appendix: source
Thrown at src/lockfile/graph.rs:138
return Ok(self.clone());
};
let text = std::fs::read_to_string(dir.join(T::GRAPH_FILE))
.map_err(|e| eyre!("dependency sidecar {}: {e}; run `mise lock`", dir.display()))?;
let graph = T::read(dir, text)
.map_err(|e| eyre!("dependency sidecar {}: {e}; run `mise lock`", dir.display()))?;
Ok(Self::Inline {
graph,
dir: Some(dir.clone()),
digest: OnceLock::new(),
})
}
pub(crate) fn resolve_path(&mut self, lockfile: &Path) -> Result<()> {
if let Self::Sidecar { dir, .. } = self {
if dir.is_absolute()
|| dir.components().any(|c| !matches!(c, Component::Normal(_)))
|| dir.to_string_lossy().contains('\\')
{
bail!("invalid dependency sidecar path {}", dir.display());
}
*dir = absolute(lockfile.parent().unwrap_or(Path::new("."))).join(&*dir);
}
Ok(())
}
pub(crate) fn parse(value: toml::Value) -> Result<Self> {
if value.get("path").is_some() {
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct Pointer {
path: PathBuf,
digest: String,
}
let p: Pointer = value.try_into()?;
if !p
.digest
.strip_prefix("sha256:")
.is_some_and(|s| s.len() == 64 && s.bytes().all(|b| b.is_ascii_hexdigit()))View on GitHub (pinned to 533346cc37)