zed-industries/zed · error

failed to upload via docker cp {} -> {}: {}

Error message

failed to upload via docker cp {} -> {}: {}

What it means

The Docker transport uploads the zed-remote-server binary into the container via `docker cp -a <src> <container_id>:<dst>`; this error is raised when that docker cp invocation exits non-zero and embeds the CLI's stderr. It is a failure of the docker CLI copy operation itself, not of Zed's upload logic.

Source

Thrown at crates/remote/src/transport/docker.rs:451

    async fn upload_and_chown(
        docker_cli: String,
        connection_options: DockerConnectionOptions,
        src_path: String,
        dst_path: String,
    ) -> Result<()> {
        let mut command = util::command::new_command(&docker_cli);
        command.kill_on_drop(true);
        command.arg("cp");
        command.arg("-a");
        command.arg(&src_path);
        command.arg(format!("{}:{}", connection_options.container_id, dst_path));

        let output = command.output().await?;

        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            log::debug!("failed to upload via docker cp {src_path} -> {dst_path}: {stderr}",);
            anyhow::bail!(
                "failed to upload via docker cp {} -> {}: {}",
                src_path,
                dst_path,
                stderr,
            );
        }

        let mut chown_command = util::command::new_command(&docker_cli);
        chown_command.kill_on_drop(true);
        chown_command.arg("exec");
        chown_command.arg(connection_options.container_id);
        chown_command.arg("chown");
        chown_command.arg(format!(
            "{}:{}",
            connection_options.remote_user, connection_options.remote_user,
        ));
        chown_command.arg(&dst_path);

View on GitHub (pinned to 5a9b9558db)

Solutions

  1. Confirm the container is still running and the id resolves: `docker ps`, then reconnect so Zed re-resolves the connection
  2. Reproduce manually with the exact paths from the message: `docker cp -a <src> <container>:<dst>` and read the embedded stderr
  3. Ensure the destination directory exists and is writable inside the container (`docker exec <id> mkdir -p <dst_dir>`)
  4. Check docker storage health (`docker system df`, daemon logs) if the daemon reports ENOSPC or internal errors

Example fix

# before: destination dir absent in image, docker cp fails
FROM scratch
COPY app /app

# after
FROM alpine
RUN mkdir -p /root/.local/share/zed
COPY app /app
Defensive patterns

Strategy: retry

Validate before calling

fn container_running(output: &str, container_id: &str) -> bool {
    output.lines().any(|l| l.trim().starts_with(container_id))
}
// run: docker ps --no-trunc --filter id=<container_id>

Try / catch

let mut attempt = 0;
loop {
    match connection.upload_file(src, dest, dir).await {
        Ok(()) => break,
        Err(e) if e.to_string().contains("docker cp") && attempt < 2 => {
            attempt += 1;
            wait_for_container(container_id).await; // verify running before retry
        }
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: DockerExecConnection::upload_file executes docker cp against connection_options.container_id and the command fails: container not running, stale/wrong container id, destination directory missing or read-only, disk full, or docker daemon errors.

Common situations: Container exited or was recreated between connect and upload; destination parent directory never created in a minimal image; read-only root filesystem; rootless docker permission problems; no space left on the docker storage driver.

Related errors


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