jdx/mise · error

bootstrap_command returned an unsafe mise path: {command:?}

Error message

bootstrap_command returned an unsafe mise path: {command:?}

What it means

When no provisioning strategy is configured, mise discovers mise on the remote by running a login-shell script and requires the result to be an absolute path (starting with '/') free of NUL, newline, and carriage return. validated_remote_command rejects the discovered path when that contract breaks, because it is later executed verbatim on the remote.

Source

Thrown at src/system/remote.rs:1647

    if value.is_empty() || value.contains('\0') {
        bail!("remote {kind} cannot be empty or contain NUL");
    }
    Ok(())
}

fn validate_staging_path(path: &str) -> Result<()> {
    if !path.starts_with("/tmp/mise-bootstrap.")
        || path["/tmp/mise-bootstrap.".len()..].is_empty()
        || path.chars().any(char::is_whitespace)
    {
        bail!("remote mktemp returned an unsafe staging path: {path:?}");
    }
    Ok(())
}

fn validated_remote_command(command: &str) -> Result<String> {
    if !command.starts_with('/') || command.contains(['\0', '\n', '\r']) {
        bail!("bootstrap_command returned an unsafe mise path: {command:?}");
    }
    Ok(command.to_string())
}

fn validated_remote_command_output(output: &str) -> Result<String> {
    validated_remote_command(output.strip_suffix('\n').unwrap_or(output))
}

fn validated_absolute_remote_path_output(output: &str, kind: &str) -> Result<String> {
    let path = output.strip_suffix('\n').unwrap_or(output);
    if !path.starts_with('/') || path.contains(['\0', '\n', '\r']) {
        bail!("{kind} returned an unsafe absolute path: {path:?}");
    }
    Ok(path.to_string())
}

fn validate_remote_executable(command: &str) -> Result<()> {
    validate_value("mise command", command)?;

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Check what the probe actually returns: ssh <dest> sh -lc 'command -v mise' — you should see exactly one absolute path line
  2. Remove or silence startup output in the remote login shell (.profile/.bash_profile/.zprofile MOTD echoes) so the only stdout is the path
  3. If discovery cannot be made clean, bypass it by setting remote_mise = "/usr/local/bin/mise" (or mise_bin/bootstrap_command) under [remote.<name>]
  4. If the printed path is relative, reinstall mise on the remote so 'command -v mise' resolves to an absolute path

Example fix

# before: [remote.prod] host = "build.example.com" # discovery polluted by remote profile output
# after:
[remote.prod]
host = "build.example.com"
remote_mise = "/usr/local/bin/mise"
Defensive patterns

Strategy: validation

Validate before calling

path=$(ssh "$dest" sh -lc 'command -v mise')
case "$path" in /*) [ "$(printf '%s' "$path" | wc -l) -eq 1 ] || echo "multi-line output, profile noise" >&2;; *) echo "mise not resolvable to absolute path on remote" >&2;; esac

Prevention

When it happens

Trigger: resolve_remote_mise() running 'sh -lc <remote_mise_output_script>' when mise_bin/remote_mise/bootstrap_command are all unset: the resolved mise path comes back relative (odd shim or function printing a relative path), or stdout contains extra lines or CRLF because the remote profile prints banners or a Windows-style line ending is emitted.

Common situations: Remote hosts whose login shell prints MOTD/banner text before the path, mise installed via a shell function or alias that echoes something other than an absolute path, .profile lines like 'echo $SHELL', and remotes where /usr/local/bin/mise is a relative symlink resolved oddly.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/befd664e7e1095aa. Report an issue: GitHub.