zed-industries/zed · error
failed to change ownership for zed_remote_server via chown:
Error message
failed to change ownership for zed_remote_server via chown: {} What it means
After docker cp succeeds, Zed runs `docker exec <container> chown <remote_user>:<remote_user> <dst_path>` so the uploaded remote server is owned by the connecting user. This error means that chown exited non-zero and its stderr is included verbatim.
Source
Thrown at crates/remote/src/transport/docker.rs:477
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);
let output = chown_command.output().await?;
if output.status.success() {
return Ok(());
}
let stderr = String::from_utf8_lossy(&output.stderr);
log::debug!("failed to change ownership for via chown: {stderr}",);
anyhow::bail!(
"failed to change ownership for zed_remote_server via chown: {}",
stderr,
);
}
async fn upload_file(
&self,
src_path: &Path,
dest_path: &RelPath,
remote_dir_for_server: &str,
) -> Result<()> {
log::debug!("uploading file {:?} to {:?}", src_path, dest_path);
let src_path_display = src_path.display().to_string();
let dest_path_str = dest_path.display(self.path_style());
let full_server_path = format!("{}/{}", remote_dir_for_server, dest_path_str);View on GitHub (pinned to 5a9b9558db)
Solutions
- Verify the user exists: `docker exec <id> id <remote_user>`; if missing, add it (alpine: `adduser -D <user>`) or connect as a user present in the image
- Run the failing command manually to see the exact stderr: `docker exec <id> chown <user>:<user> <dst_path>`
- Connect as root, or use an image where the connecting user can chown its own files
- For rootless/userns docker, confirm the uid mapping covers the remote user's uid
Example fix
# before FROM alpine COPY app /app # after FROM alpine RUN adduser -D devuser COPY --chown=devuser:devuser app /app USER devuser
Defensive patterns
Strategy: try-catch
Validate before calling
async fn user_exists_in_container(conn: &DockerExecConnection, user: &str) -> bool {
conn.run_docker_exec("id", None, &Default::default(), &[user])
.await
.is_ok()
} Try / catch
if let Err(e) = result {
if e.to_string().contains("chown") {
// surface stderr and suggest adding remote_user to the image or connecting as root
}
return Err(e);
} Prevention
- Create the connecting user in the image (adduser/useradd) with ownership of the server dir
- Use COPY --chown in Dockerfiles for preinstalled binaries
- Avoid rootless/userns-remap mismatch by verifying `docker exec <id> id <user>` before connecting
When it happens
Trigger: chown fails inside the container: remote_user has no entry in the container's /etc/passwd, docker exec runs as a user lacking CAP_CHOWN, the destination path is on a read-only filesystem, or user namespace remapping shifts the uid/gid.
Common situations: Connecting with a username that was never added to the image; minimal images (alpine without shadow, distroless) with no user provisioning; rootless docker or userns-remap installs where ids map differently; images mounted read-only.
Related errors
- failed to upload via docker cp {} -> {}: {}
- Neither curl nor wget is available
- ZedPierAgent requires EVAL_CLI_CONTAINER_PATH (the eval-cli
- Failed to install or start judge proxy (exit {result.return_
- error running osascript: {}
AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20).
Data as JSON: /api/errors/abe854c914918f52.
Report an issue: GitHub.