{"record":{"id":"c04701c9f7c3c1b2","repo":"jdx/mise","slug":"remote-mktemp-returned-an-unsafe-staging-path-pa","errorCode":null,"errorMessage":"remote mktemp returned an unsafe staging path: {path:?}","messagePattern":"remote mktemp returned an unsafe staging path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/remote.rs","lineNumber":1640,"sourceCode":"    if value.starts_with('-') || value.chars().any(char::is_whitespace) {\n        bail!(\"invalid remote {kind}: {value}\");\n    }\n    Ok(())\n}\n\nfn validate_value(kind: &str, value: &str) -> Result<()> {\n    if value.is_empty() || value.contains('\\0') {\n        bail!(\"remote {kind} cannot be empty or contain NUL\");\n    }\n    Ok(())\n}\n\nfn validate_staging_path(path: &str) -> Result<()> {\n    if !path.starts_with(\"/tmp/mise-bootstrap.\")\n        || path[\"/tmp/mise-bootstrap.\".len()..].is_empty()\n        || path.chars().any(char::is_whitespace)\n    {\n        bail!(\"remote mktemp returned an unsafe staging path: {path:?}\");\n    }\n    Ok(())\n}\n\nfn validated_remote_command(command: &str) -> Result<String> {\n    if !command.starts_with('/') || command.contains(['\\0', '\\n', '\\r']) {\n        bail!(\"bootstrap_command returned an unsafe mise path: {command:?}\");\n    }\n    Ok(command.to_string())\n}\n\nfn validated_remote_command_output(output: &str) -> Result<String> {\n    validated_remote_command(output.strip_suffix('\\n').unwrap_or(output))\n}\n\nfn validated_absolute_remote_path_output(output: &str, kind: &str) -> Result<String> {\n    let path = output.strip_suffix('\\n').unwrap_or(output);\n    if !path.starts_with('/') || path.contains(['\\0', '\\n', '\\r']) {","sourceCodeStart":1622,"sourceCodeEnd":1658,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/remote.rs#L1622-L1658","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before (remote ~/.zshenv): echo \"welcome to buildhost\" # every sh -lc call on zsh remotes emits this, polluting mktemp output\n# after:\n[[ -o interactive ]] && echo \"welcome to buildhost\"","handlingStrategy":"validation","validationCode":"out=$(ssh \"$dest\" 'mktemp -d /tmp/mise-bootstrap.XXXXXX')\ncase \"$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","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["ssh","remote-bootstrap","mktemp","output-validation","mise"],"backgroundTag":"remote-shell-output-pollution","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}