jdx/mise · error
invalid tool ref {s:?}: contains forbidden character {c:?}
Error message
invalid tool ref {s:?}: contains forbidden character {c:?} What it means
validate_ref_string rejects ref values containing any character matched by is_forbidden_version_char; the message names the first offending character. Refs share the version vocabulary to keep them safe as filenames and CLI arguments.
Source
Thrown at src/toolset/tool_request.rs:655
}
/// 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 rather
/// than being allowed through — see that function. The shell those hooks run through there is
/// `cmd.exe`, whose metacharacters are a different set, so a few more are rejected on Windows —
/// see [`is_forbidden_path_char`].View on GitHub (pinned to afd2eddd3a)
Solutions
- Remove or rename the offending character in the branch/tag name (the error names it explicitly).
- Quote and trim shell expansions before composing the ref string.
- For unusual names, pin a commit with `rev:<sha>` instead of the raw name.
Example fix
// before
node = { tag = "v1.0 final" }
// after
node = { tag = "v1.0-final" } Defensive patterns
Strategy: validation
Validate before calling
function isValidRefChars(ref) { return typeof ref === 'string' && !/[\s'";`$&|<>(){}\[\]\\]/.test(ref); }
if (!isValidRefChars(ref)) throw new Error(`ref has forbidden characters: ${ref}`); Type guard
function isPlainRef(v) { return typeof v === 'string' && /^[\w./+-]+$/.test(v); } Prevention
- Avoid branch/tag names containing spaces or shell metacharacters.
- Quote and trim template/shell expansions before composing ref strings.
- Replace awkward names with `rev:<sha>` pins in automation.
When it happens
Trigger: A `ref:`/`branch:`/`tag:`/`rev:` value containing characters like spaces, quotes, semicolons, or other disallowed symbols, e.g. `node@ref:my branch` or `tag = "v1.0 (rc)"`.
Common situations: Branch names with spaces or special characters produced by templating/shell expansion, quotes copied from web pages, or shell interpolation injecting separators into the ref slot.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- invalid tool ref {s:?}: must not start with '-'
- --connect-timeout must be greater than zero
- a glob is required
- {target_raw}: target must be absolute or start with ~/
- Directory specified with --cd does not exist: {} Please chec
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/3a643f48f708d9bf.
Report an issue: GitHub.