jdx/mise · error
remote mktemp returned an unsafe staging path: {path:?}
Error message
remote mktemp returned an unsafe staging path: {path:?} What it means
mise creates a staging directory on the remote with mktemp (/tmp/mise-bootstrap.XXXXXX) and requires the printed path to match exactly that prefix plus a non-empty suffix with no whitespace. This error means the path mise read back from the remote's stdout does not satisfy that contract, so it refuses to rm -rf or write into it.
Source
Thrown at src/system/remote.rs:1640
if value.starts_with('-') || value.chars().any(char::is_whitespace) {
bail!("invalid remote {kind}: {value}");
}
Ok(())
}
fn validate_value(kind: &str, value: &str) -> Result<()> {
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']) {View on GitHub (pinned to 6f52dcdf99)
Solutions
- Reproduce: ssh <dest> 'mktemp -d /tmp/mise-bootstrap.XXXXXX' and check the output is exactly one /tmp/mise-bootstrap.<suffix> line
- Silence remote startup noise: remove or guard echo/printf statements in the remote user's .zshenv/.profile/.bashrc so non-interactive shells print nothing
- Ensure TMPDIR is unset or points at /tmp on the remote, since the check requires the literal /tmp/mise-bootstrap. prefix
- After fixing, re-run mise bootstrap remote; the staging path check runs on every attempt
Example fix
# before (remote ~/.zshenv): echo "welcome to buildhost" # every sh -lc call on zsh remotes emits this, polluting mktemp output # after: [[ -o interactive ]] && echo "welcome to buildhost"
Defensive patterns
Strategy: validation
Validate before calling
out=$(ssh "$dest" 'mktemp -d /tmp/mise-bootstrap.XXXXXX') case "$out" in /tmp/mise-bootstrap.?*) [ "$(printf '%s' "$out" | wc -l) -eq 1 ] || echo "staging output polluted: $out" >&2;; *) echo "unsafe staging path: $out" >&2;; esac
Prevention
- Keep remote dotfiles silent for non-interactive shells ([[ -o interactive ]] guards around echo)
- Do not redirect TMPDIR away from /tmp on hosts used for mise bootstrap remote
- Test remote mktemp output manually after changing remote shell config
When it happens
Trigger: In run() after 'sh -c <staging_creation_script>': remote shell startup files (.zshenv, profile, MOTD logic) print extra lines so the trimmed stdout becomes multi-line; remote TMPDIR redirects mktemp elsewhere (path no longer starts with /tmp/mise-bootstrap.); mktemp prints a path containing a space or the template suffix is empty.
Common situations: Remote accounts with chatty dotfiles that echo text on every shell invocation (common on shared build hosts), zsh remotes where .zshenv always runs even for non-interactive commands, hardened remotes where TMPDIR points at a custom location, and CR/LF translation mangling output.
Related errors
- bootstrap_command returned an unsafe mise path: {command:?}
- automatic cross-platform provisioning is unavailable from a
- remote platform response is incomplete
- remote platform response is invalid
- remote upload to '{}' failed with {status}
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/c04701c9f7c3c1b2.
Report an issue: GitHub.