jdx/mise · error
invalid tool ref : contains path-traversal sequence
Error message
invalid tool ref {s:?}: contains path-traversal sequence What it means
Ref strings (ref:/branch:/tag:/rev: values) may not contain the '..' path-traversal sequence, since refs feed into path and argument construction. validate_ref_string rejects any such value during ToolRequest creation.
Solutions
- Use a single concrete ref name without '..'.
- For git ranges/refspecs, resolve to a concrete branch/tag/commit first and reference that.
- Fix generators/scripts emitting '..' into version fields.
Example fix
// before
node = { version = "ref:main..dev" }
// after
node = { version = "ref:dev" } Defensive patterns
Strategy: validation
Validate before calling
function validRef(r) {
return typeof r === 'string' && !r.includes('..');
} Prevention
- Never put git ranges/refspecs (a..b) in ref fields.
- Resolve to a concrete commit SHA when in doubt.
- Add config linting that rejects '..' in version/ref values.
When it happens
Trigger: A ref value containing '..' (e.g. ref:../evil, branch:a..b) passed through new_with_options or config parsing.
Common situations: Pasting a relative path into a ref field; git refspecs or ranges (a..b) supplied where a single ref name is required; generated config interpolation errors.
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 tool version
- brew-cask: completion target
- brew-cask: invalid
- brew-cask: invalid structured flight path
- remote cache path escapes its output root
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/4369fcb759977369.
Report an issue: GitHub.
Appendix: source
Thrown at src/toolset/tool_request.rs:742
bail!("invalid tool version {s:?}: contains forbidden character {c:?}");
}
Ok(())
}
/// Validate `ref:`/`branch:`/`tag:`/`rev:` values. Same character rules as
/// version strings: branch/tag names already use the same broad vocabulary
/// (`/`, `+`, `-`, etc.), so only shell-quote-breaking characters and leading
/// dashes need rejection. Kept as a separate function for distinct error
/// messages.
fn validate_ref_string(s: &str) -> Result<()> {
if s.is_empty() {
return Ok(());
}
if s.starts_with('-') {
bail!("invalid tool ref {s:?}: must not start with '-'");
}
if s.contains("..") {
bail!("invalid tool ref {s:?}: contains path-traversal sequence");
}
if let Some(c) = s.chars().find(|c| is_forbidden_version_char(*c)) {
bail!("invalid tool ref {s:?}: contains forbidden character {c:?}");
}
Ok(())
}
/// Validate `path:` values. Filesystem paths legitimately contain `/`, spaces,
/// and many other characters, but the resolved path becomes `ctx.rootPath` /
/// `installPath` for path-mode tools and is interpolated into shell commands
/// by some plugin hooks. Reject the same shell-quote-breaking characters as
/// version strings — `$`, backtick, quotes, and `\` — so a hostile `path:`
/// entry in a project config cannot inject shell syntax. Path traversal is
/// intentionally not rejected here because `path:../tools/foo` is a normal
/// relative-path use case.
///
/// The list is written for a POSIX shell, which is why `\` is on it. On Windows `\` is a path
/// separator instead, so it is rewritten by [`windows_path_separators`] before it gets here ratherView on GitHub (pinned to 533346cc37)