jdx/mise · error · eyre::Report
remote upload to '{}' failed with {status}
Error message
remote upload to '{}' failed with {status} What it means
Thrown by SshSession::status_with_stdin when the binary-upload pipeline ('ssh host sh -c "cat > <remote path> ..."' with the file on stdin) exits non-zero. The upload is a streamed cat over ssh, so failures come from the remote side of that pipeline: unwritable/missing target directory, full disk, quota, connection drops mid-stream, or ssh-level auth/network errors.
Source
Thrown at src/system/remote.rs:1538
let status = Command::new(&self.ssh).args(args).status()?;
if !status.success() {
bail!(
"remote command on '{}' failed with {status}",
self.host.name
);
}
Ok(())
}
fn status_with_stdin(&self, remote_argv: &[&str], input: File) -> Result<()> {
let args = self.args(false, remote_argv);
info!("$ {} {}", self.ssh.display(), shell_words::join(&args));
let status = Command::new(&self.ssh)
.args(args)
.stdin(Stdio::from(input))
.status()?;
if !status.success() {
bail!("remote upload to '{}' failed with {status}", self.host.name);
}
Ok(())
}
fn upload_executable(&self, local: &Path, remote: &str) -> Result<()> {
let file = File::open(local)
.wrap_err_with(|| format!("failed to open mise binary {}", local.display()))?;
self.status_with_stdin(
&[
"sh",
"-c",
&format!(
"cat > {} && chmod 700 {}",
shell_quote(remote),
shell_quote(remote)
),
],
file,View on GitHub (pinned to 6f52dcdf99)
Solutions
- Check the remote preconditions: ssh <host> 'test -w <dir> && df -h <dir>' for the target directory and free space
- Fix permissions/ownership of the remote target path for the configured SSH user
- For ssh 255, resolve auth/connectivity (identity_file, port, ConnectTimeout) before retrying the upload
- Retry after freeing disk space — mid-stream drops are transient on unstable links
Example fix
# before: upload target missing/unwritable ssh deploy@web-1 'ls -ld /home/deploy/.local/share/mise' # No such file or directory # fix on remote ssh deploy@web-1 'mkdir -p ~/.local/share/mise && chmod u+w ~/.local/share/mise' # then re-run: mise bootstrap --host web-1
Defensive patterns
Strategy: retry
Validate before calling
# Pre-flight the upload destination before triggering provisioning: ssh deploy@web-1 'DIR="$(dirname /path/to/target)"; test -d "$DIR" && test -w "$DIR" && df -h "$DIR" || echo PRECONDITION-FAILED'
Try / catch
let mut attempt = 0;
loop {
attempt += 1;
match session.upload_executable(&local, remote_path).await {
Err(e) if attempt < 3 && e.to_string().contains("remote upload") => {
tokio::time::sleep(std::time::Duration::from_secs(2u64 * attempt)).await; // transient reset: backoff and retry
}
other => break other?,
}
} Prevention
- Ensure the SSH user owns/can write the remote staging directory before first deploy
- Monitor remote disk space; uploads fail mid-stream when full
- Distinguish auth/255 failures (fix config) from mid-stream drops (safe to retry)
When it happens
Trigger: Remote staging directory does not exist or lacks write permission for the SSH user; remote filesystem full (exit from cat/dd); connection reset during a large binary transfer; ssh 255 because keys/BatchMode blocked auth.
Common situations: First deploy to a fresh host without the expected directory layout; small VPS disks filling up; restrictive umask/ACLs on shared hosts; flaky networks truncating long uploads.
Related errors
- automatic cross-platform provisioning is unavailable from a
- remote platform response is incomplete
- remote platform response is invalid
- remote command on '{name}' failed with {}: {}
- remote mktemp returned an unsafe staging path: {path:?}
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/2a140579b02f503f.
Report an issue: GitHub.