nikivdev/code · error
Refusing to overwrite {}
Error message
Refusing to overwrite {} What it means
copy_dir_all recursively copies a directory tree, and before writing each entry it checks whether the corresponding target path already exists, bailing with 'Refusing to overwrite <path>' if so. This is an explicit non-destructive guarantee: the copier never clobbers existing files or directories, and it fails at the first collision instead of merging silently.
Source
Thrown at src/code.rs:857
err.raw_os_error() == Some(libc::EXDEV)
}
#[cfg(not(unix))]
{
let _ = err;
false
}
}
fn copy_dir_all(from: &Path, to: &Path) -> Result<()> {
fs::create_dir_all(to).with_context(|| format!("failed to create {}", to.display()))?;
for entry in fs::read_dir(from).with_context(|| format!("failed to read {}", from.display()))? {
let entry = entry?;
let path = entry.path();
let file_type = entry.file_type()?;
let target = to.join(entry.file_name());
if target.exists() {
bail!("Refusing to overwrite {}", target.display());
}
if file_type.is_dir() {
copy_dir_all(&path, &target)?;
} else if file_type.is_file() {
fs::copy(&path, &target)
.with_context(|| format!("failed to copy {}", path.display()))?;
} else if file_type.is_symlink() {
let link_target = fs::read_link(&path)
.with_context(|| format!("failed to read link {}", path.display()))?;
copy_symlink(&link_target, &target)?;
}
}
Ok(())
}
fn copy_symlink(target: &Path, dest: &Path) -> Result<()> {
#[cfg(unix)]View on GitHub (pinned to a747e741ae)
Solutions
- Delete or move the existing destination directory, then re-run the copy.
- Choose a fresh target path that does not exist.
- If a previous run failed midway, remove the partial output first — the copier is not resumable.
- Compare source and destination trees beforehand (e.g. `rsync -n`) to find which entries collide.
Example fix
// before
copy_dir_all(&template, &target)?; // target/config.toml already exists
// after
if target.exists() {
fs::remove_dir_all(&target)?; // or pick a new target
}
copy_dir_all(&template, &target)?; Defensive patterns
Strategy: try-catch
Validate before calling
fn target_is_clear(src: &Path, dst: &Path) -> bool {
!dst.exists() || !walkdir::WalkDir::new(src).into_iter().any(|e| {
e.map(|e| dst.join(e.file_name()).exists()).unwrap_or(true)
})
} Try / catch
match copy_dir_all(src, dst) {
Err(e) if e.to_string().starts_with("Refusing to overwrite") => {
let path = e.to_string().trim_start_matches("Refusing to overwrite ");
eprintln!("Collision at {path}: remove the existing destination and retry.");
}
other => other?,
} Prevention
- Ensure the destination directory is empty (or absent) before copying.
- After a failed copy, delete the partial output before retrying — retries are not resumable.
- Pick unique target names (timestamps, hashes) for repeated template instantiations.
When it happens
Trigger: Calling any of copy_dir_all's callers (new_from_template, new_project, migrate_project, migrate_to_path, move_dir, or copy_dir_all recursively) when the destination tree already contains any file or directory that the source tree would create — including a partially-created target left by a previous failed run (copy_dir_all recurses into itself, so a retry after a mid-copy failure hits this on the leftover files).
Common situations: Re-running `new` with a template into an existing folder; retrying a migration that crashed halfway, leaving partial output; template files colliding with files created by ensure_dir/other steps; case-insensitive filesystems colliding on names differing only by case.
Related errors
- Refusing to overwrite {}
- Refusing to overwrite {}
- {} already exists; refusing to overwrite
- jj git export retry loop should always return
- fzf not found on PATH – install it to use fuzzy selection.
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/c6b5223e1f7ee6f4.
Report an issue: GitHub.