jdx/mise · error · eyre::Report
{option}: '{path}' must be a safe relative path (no absolute
Error message
{option}: '{path}' must be a safe relative path (no absolute paths or parent directories) What it means
mise validates the `bin` (and `rename target`) option with `file::is_safe_relative_path`: it must be a non-empty relative path whose components are all normal (no leading `/`, no `C:` drive prefix, no `..` segments). This preserves the accepted `bin = "bin/tool"` form while rejecting absolute or parent-escaping paths that would resolve the binary outside the install directory. Thrown at option-parse time in static backends (src/backend/static_helpers.rs:587, :794, :900; src/backend/http.rs:405).
Source
Thrown at src/backend/static_helpers.rs:1145
/// Rejects `bin`/`rename_exe` names that are not plain file names (`../tool`,
/// `/abs/tool`, `bin/tool`), which would otherwise be joined onto the install
/// or search directory and place the binary outside it.
pub fn ensure_plain_bin_name(option: &str, name: &str) -> eyre::Result<()> {
if !file::is_plain_file_name(name) {
bail!(
"{option}: '{name}' must be a plain file name \
(no path separators or parent directories)"
);
}
Ok(())
}
/// Rejects a configured binary path that is absolute or contains parent
/// components, while preserving the established `bin = "bin/tool"` form.
pub fn ensure_safe_relative_bin_path(option: &str, path: &str) -> eyre::Result<()> {
if !file::is_safe_relative_path(path) {
bail!(
"{option}: '{path}' must be a safe relative path \
(no absolute paths or parent directories)"
);
}
Ok(())
}
/// Renames `path` (named `file_name`) to `target` within `dir`, preserving any
/// required extension and ensuring the result is executable. A collision on the
/// target (two mappings pointing at the same name, or the archive already
/// containing that name) is unsatisfiable, so it fails the install loudly rather
/// than silently dropping a binary and reporting success.
fn finish_rename(dir: &Path, path: &Path, file_name: &str, target: &str) -> eyre::Result<()> {
let target_path = keep_required_extensions(dir, file_name, target, dir.join(target));
// Ensure the binary is executable whether or not we move it: ZIP archives drop
// the exec bit, and the file may already carry the desired name.
if !file::is_executable(path) {
file::make_executable(path)?;View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Make the value relative to the tool's install directory, e.g. bin = "bin/tool" or bin = "tool"
- Remove leading slashes/backslashes and drive prefixes; replace `..` segments with the real relative location inside the archive
- If you genuinely need an absolute path to an external binary, that is not what `bin` does — reference the executable via shims or PATH instead
Example fix
# before (mise.toml)
[tools.http]
mytool = { url = 'https://example.com/t.tar.gz', bin = '/usr/local/bin/mytool' }
# after
[tools.http]
mytool = { url = 'https://example.com/t.tar.gz', bin = 'bin/mytool' } Defensive patterns
Strategy: validation
Validate before calling
# Rust: mirror of file::is_safe_relative_path
fn is_safe_relative_bin(s: &str) -> bool {
if s.is_empty() { return false; }
let n = s.replace('\\', "/");
let b = n.as_bytes();
if n.starts_with('/') || (b.len() >= 2 && b[0].is_ascii_alphabetic() && b[1] == b':') {
return false;
}
n.components().all(|c| matches!(c, std::path::Component::Normal(_)))
}
assert!(is_safe_relative_bin("bin/tool"));
assert!(!is_safe_relative_bin("../tool")); Prevention
- Write `bin` paths relative to the tool's install dir, never absolute
- Avoid `..` and drive letters in mise.toml tool options
- Test config with `mise install` in a scratch project before committing
When it happens
Trigger: Setting `bin = "/usr/local/bin/tool"`, `bin = "../../usr/bin/tool"`, `bin = "C:\\tools\\tool.exe"`, or `bin = ""` in a mise.toml tool entry backed by the http/ubi/static helpers. Any of these makes ensure_safe_relative_bin_path bail before the install proceeds.
Common situations: Users pasting an absolute system path into `bin` thinking it is the target location on disk; configs using Windows drive letters; values with trailing `..` from manually trimming a prefix; empty string left after template rendering.
Understand the failure class
Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.
Related errors
- {option}: '{name}' must be a plain file name (no path separa
- rename_exe: cannot rename '{}' to '{}': target already exist
- Unsupported forge type {:?}
- Invalid checksum: {platform_key}
- {format} format not supported
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/d00cb70fd5d1ee77.
Report an issue: GitHub.