zed-industries/zed · error

failed to upload directory via SFTP/SCP {} -> {}: {}

Error message

failed to upload directory via SFTP/SCP {} -> {}: {}

What it means

When uploading a directory (the extracted remote server) over SSH, Zed tries SFTP and falls back to scp -r; this error is the final failure of the scp fallback, embedding the CLI's stderr. Neither SFTP nor SCP managed to copy the directory to the remote host.

Source

Thrown at crates/remote/src/transport/ssh.rs:454

                if output.status.success() {
                    return Ok(());
                }

                let stderr = String::from_utf8_lossy(&output.stderr);
                log::debug!("failed to upload directory via SFTP {src_path_display} -> {dest_path_str}: {stderr}");
            }

            log::debug!("using SCP for directory upload");
            let output = scp_command.output().await?;

            if output.status.success() {
                return Ok(());
            }

            let stderr = String::from_utf8_lossy(&output.stderr);
            log::debug!("failed to upload directory via SCP {src_path_display} -> {dest_path_str}: {stderr}");

            anyhow::bail!(
                "failed to upload directory via SFTP/SCP {} -> {}: {}",
                src_path_display,
                dest_path_str,
                stderr,
            );
        })
    }

    fn start_proxy(
        &self,
        unique_identifier: String,
        reconnect: bool,
        incoming_tx: UnboundedSender<Envelope>,
        outgoing_rx: UnboundedReceiver<Envelope>,
        connection_activity_tx: Sender<()>,
        delegate: Arc<dyn RemoteClientDelegate>,
        cx: &mut AsyncApp,
    ) -> Task<Result<i32>> {

View on GitHub (pinned to f4178619ac)

Solutions

  1. Reproduce manually with the paths from the message: `scp -r <src_dir> <user>@<host>:<dest>` and read the stderr Zed embedded
  2. Install the SSH client tools on the remote (apt-get install openssh-client / apk add openssh) so scp and sftp exist
  3. Verify destination writability and free space on the remote: `df -h`, `touch <dest_dir>/probe`
  4. Silence non-interactive shell output (.bashrc guards), since shell chatter breaks SFTP/SCP sessions

Example fix

# before: remote container without openssh-clients
apk add --no-cache openssh   # run on the remote

# then retry the Zed remote connection; scp fallback now succeeds
Defensive patterns

Strategy: retry

Validate before calling

async fn remote_supports_scp(socket: &SshSocket, shell: ShellKind) -> bool {
    socket.run_command(shell, "which", &["scp"], true).await.is_ok()
        && socket.run_command(shell, "which", &["sftp"], true).await.is_ok()
}

Try / catch

match upload_dir(src, dest).await {
    Err(e) if e.to_string().contains("SFTP/SCP") && attempts_left() => {
        // verify remote writability and free space, then retry once
        retry_after_repair().await
    }
    other => other,
}

Prevention

When it happens

Trigger: The scp -r command built for the directory upload exits non-zero: the remote lacks scp/sftp binaries, the target directory is not writable, the disk is full, or the destination path/arguments trip quoting problems.

Common situations: Minimal remotes (containers, embedded boards) without openssh-clients; connecting as a user whose home or .local/share is read-only; full server filesystems; remote shell startup files printing text that corrupts the SFTP protocol channel.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/fce30fb1fa169588. Report an issue: GitHub.