jdx/mise · error

invalid tool ref {s:?}: must not start with '-'

Error message

invalid tool ref {s:?}: must not start with '-'

What it means

validate_ref_string validates `ref:`/`branch:`/`tag:`/`rev:` values with the same rules as version strings; this arm rejects a ref that begins with '-'. Starting with '-' could be misinterpreted as a CLI flag downstream, so mise refuses it during ToolRequest construction.

Source

Thrown at src/toolset/tool_request.rs:649

        bail!("invalid tool version {s:?}: contains path-traversal sequence");
    }
    if let Some(c) = s.chars().find(|c| is_forbidden_version_char(*c)) {
        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.

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Rename or re-specify the branch/tag without a leading '-', e.g. `ref:feature-x` instead of `ref:-feature-x`.
  2. If the target genuinely has a leading dash, use `rev:<full-sha>` to pin the commit instead of a name.
  3. Fix the script/config that generated the ref string and verify with `mise use node@ref:mybranch`.

Example fix

// before (mise.toml)
[tools]
"github:owner/repo" = { ref = "-dev" }
// after
[tools]
"github:owner/repo" = { ref = "dev" }
Defensive patterns

Strategy: validation

Validate before calling

function isValidRef(ref) {
  return typeof ref === 'string' && (ref === '' || (!ref.startsWith('-') && !ref.includes('..')));
}
if (!isValidRef(ref)) throw new Error(`bad ref: ${ref}`);

Type guard

function isSafeRef(v) { return typeof v === 'string' && !v.startsWith('-'); }

Prevention

When it happens

Trigger: A ToolRequest like `git:repo@ref:-weird-branch`, `node@ref:-x`, or a config entry `branch = "-feature"` passed through new_with_options.

Common situations: Branch or tag names that accidentally begin with a dash (often from scripting, e.g. `branch = "$(git symbolic-ref --short HEAD)"` returning an odd value), or typos where the prefix separator got attached to the name.

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


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/dd3b3ff74e1221ba. Report an issue: GitHub.