zed-industries/zed · error
failed to upload file via STFP/SCP {} -> {}: {}
Error message
failed to upload file via STFP/SCP {} -> {}: {} What it means
For single-file uploads over SSH, Zed tries SFTP and falls back to a plain scp command; when the scp fallback exits non-zero this error is raised with the CLI's stderr (the 'STFP' in the message is a source-level typo for SFTP). Neither SFTP nor SCP could transfer the file.
Source
Thrown at crates/remote/src/transport/ssh.rs:1290
let stderr = String::from_utf8_lossy(&output.stderr);
log::debug!(
"failed to upload file via SFTP {src_path_display} -> {dest_path_str}: {stderr}"
);
}
log::debug!("using SCP for file upload");
let mut command = self.build_scp_command(src_path, &dest_path_str, None);
let output = command.output().await?;
if output.status.success() {
return Ok(());
}
let stderr = String::from_utf8_lossy(&output.stderr);
log::debug!(
"failed to upload file via SCP {src_path_display} -> {dest_path_str}: {stderr}",
);
anyhow::bail!(
"failed to upload file via STFP/SCP {} -> {}: {}",
src_path_display,
dest_path_str,
stderr,
);
}
async fn is_sftp_available() -> bool {
which::which("sftp").is_ok()
}
}
impl SshSocket {
#[cfg(not(windows))]
async fn new(options: SshConnectionOptions, socket_path: PathBuf) -> Result<Self> {
Ok(Self {
connection_options: options,
envs: HashMap::default(),View on GitHub (pinned to f4178619ac)
Solutions
- Run scp manually with the same src/dst shown in the message to reproduce and read the stderr
- Check remote writability and space: `df -h`, `touch <dest_dir>/probe`
- Guard remote shell rc files against non-interactive output — any stdout noise breaks SFTP/SCP
- Install openssh-client on the remote if scp/sftp binaries are missing
Example fix
# before: .bashrc prints a motd, sftp protocol desynchronizes # ~/.bashrc (remote) echo "welcome" # remove/guard for non-interactive shells # after if [ -z "$PS1" ]; then return; fi echo "welcome"
Defensive patterns
Strategy: retry
Validate before calling
async fn remote_accepts_uploads(socket: &SshSocket, shell: ShellKind, dest_dir: &str) -> bool {
socket.run_command(shell, "which", &["scp"], true).await.is_ok()
&& socket
.run_command(shell, "touch", &[&format!("{dest_dir}/probe")], true)
.await
.is_ok()
} Try / catch
match upload_file(src, dest).await {
Err(e) if e.to_string().contains("STFP/SCP") && attempts_left() => {
// repair writability / shell noise, then retry the single-file upload once
retry_after_repair().await
}
other => other,
} Prevention
- Install openssh-client on the remote so scp/sftp exist
- Make rc files silent for non-interactive shells (SFTP protocol strictness)
- Probe destination writability before large uploads
When it happens
Trigger: build_scp_command's scp invocation exits non-zero for the uploaded file: scp missing on either side, permission denied on the destination, disk full, or remote shell startup output corrupting the SFTP/SCP protocol channel.
Common situations: Remotes without openssh-clients; destination dirs writable-but-not-owned or on full filesystems; .bashrc/.profile echoing text that breaks sftp's strict protocol; filenames needing shell quoting.
Related errors
- failed to upload directory via SFTP/SCP {} -> {}: {}
- build ids may only contain lowercase letters, numbers, '.',
- registry dataset requires a name
- cannot open repository on disconnected remote machine
- unknown uname: {uname:?}
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/358c891c44633a33.
Report an issue: GitHub.