{"record":{"id":"e1b246a1ec584611","repo":"jdx/mise","slug":"remote-command-on-failed-with-status","errorCode":null,"errorMessage":"remote command on '{}' failed with {status}","messagePattern":"remote command on '(.+?)' failed with (.+?)","errorType":"exception","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/system/remote.rs","lineNumber":1522,"sourceCode":"        }\n        args.push(self.host.destination());\n        args.push(shell_words::join(remote_argv));\n        args\n    }\n\n    fn output(&self, remote_argv: &[&str]) -> Result<String> {\n        let args = self.args(false, remote_argv);\n        info!(\"$ {} {}\", self.ssh.display(), shell_words::join(&args));\n        let output = Command::new(&self.ssh).args(&args).output()?;\n        checked_output(output, &self.host.name)\n    }\n\n    fn status(&self, remote_argv: &[&str], tty: bool) -> Result<()> {\n        let args = self.args(tty, remote_argv);\n        info!(\"$ {} {}\", self.ssh.display(), shell_words::join(&args));\n        let status = Command::new(&self.ssh).args(args).status()?;\n        if !status.success() {\n            bail!(\n                \"remote command on '{}' failed with {status}\",\n                self.host.name\n            );\n        }\n        Ok(())\n    }\n\n    fn status_with_stdin(&self, remote_argv: &[&str], input: File) -> Result<()> {\n        let args = self.args(false, remote_argv);\n        info!(\"$ {} {}\", self.ssh.display(), shell_words::join(&args));\n        let status = Command::new(&self.ssh)\n            .args(args)\n            .stdin(Stdio::from(input))\n            .status()?;\n        if !status.success() {\n            bail!(\"remote upload to '{}' failed with {status}\", self.host.name);\n        }\n        Ok(())","sourceCodeStart":1504,"sourceCodeEnd":1540,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/remote.rs#L1504-L1540","documentation":"Thrown by SshSession::status after an ssh-invoked remote command exits with a non-zero status. This is a pass-through: the status is whatever the remote command (or ssh itself) returned — a failing remote mise invocation, a missing remote executable, or ssh-level failures such as authentication errors and connection timeouts (ssh conventionally exits 255). The message names the configured host and the raw exit status.","triggerScenarios":"Any remote command mise runs on your behalf failing: the actual task command exiting non-zero (intended propagation), 'remote_mise version' failing because the remote mise is broken, or ssh exiting 255 on unreachable host / bad key / refused connection.","commonSituations":"Deployed command genuinely fails on the remote; remote mise installation broken after bootstrap; wrong port/identity_file in the host config; sshd rate limits or DNS problems surfacing as 255.","solutions":["Reproduce manually to see stderr: ssh <user@host> '<the same command>' — mise only surfaces the exit code here","If ssh itself failed (255), fix connectivity/auth: check port, identity_file, ConnectTimeout, and BatchMode=yes (no password prompt when stderr is not a TTY)","If the remote command legitimately failed, fix the remote side; the exit code is faithfully propagated, not a mise bug","Run 'mise --version' equivalent on the remote (ssh host 'mise version') to confirm the remote install is healthy"],"exampleFix":"# diagnose: the error only carries the exit status\nssh -o ConnectTimeout=10 deploy@web-1 'mise exec -- node -v'\n# e.g. output: bash: mise: command not found  -> remote_mise path wrong\n\n# fix (mise.toml)\n[bootstrap.remote.hosts.web]\nhost = \"deploy@web-1\"\nremote_mise = \"/usr/local/bin/mise\"  # absolute path that exists on the remote","handlingStrategy":"try-catch","validationCode":"# Pre-flight the exact remote command and ssh auth before automating:\nssh -o ConnectTimeout=10 -o BatchMode=yes deploy@web-1 'mise version && <your-command> --dry-run' || {\n  echo \"remote precondition failed; fix auth/installation first\"\n}","typeGuard":null,"tryCatchPattern":"match session.status(&argv, tty) {\n    Err(e) => {\n        let msg = e.to_string();\n        if let Some(code) = msg.rsplit(' ').next().and_then(|s| s.trim().parse::<i32>().ok()) {\n            if code == 255 {\n                return Err(e.wrap_err(\"ssh itself failed (auth/connectivity), not the remote command\"));\n            }\n            std::process::exit(code); // propagate the remote command's real exit code\n        }\n        return Err(e);\n    }\n    Ok(()) => {}\n}","preventionTips":["Keep remotes' mise healthy: periodically run 'ssh <host> mise version' from monitoring","Use BatchMode-compatible auth (keys, identity_file) so non-TTY runs can't hang on passwords","Remember the exit status is intentional pass-through: scripts should treat it as the remote command's own code"],"tags":["mise","ssh","remote-command","exit-code","pass-through","connectivity"],"backgroundTag":"remote-command-nonzero-exit","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}