{"record":{"id":"4c8bbc61dcd740b1","repo":"zed-industries/zed","slug":"target-item-already-exists","errorCode":null,"errorMessage":"{target_item:?} already exists","messagePattern":"(.+?) already exists","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fs/src/fs.rs","lineNumber":3494,"sourceCode":"        });\n\n        match result {\n            Ok(_) => {\n                state.trash.lock().remove(trash_id);\n                state.emit_event([(path.clone(), Some(PathEventKind::Created))]);\n                Ok(path)\n            }\n            Err(_) => {\n                // For now we'll just assume that this failed because it was a\n                // collision error, which I think that, for the time being, is\n                // the only case where this could fail?\n                Err(TrashRestoreError::Collision { path })\n            }\n        }\n    }\n\n    #[cfg(feature = \"test-support\")]\n    fn as_fake(&self) -> Arc<FakeFs> {\n        self.this.upgrade().unwrap()\n    }\n}\n\npub async fn copy_recursive<'a>(\n    fs: &'a dyn Fs,\n    source: &'a Path,\n    target: &'a Path,\n    options: CopyOptions,\n) -> Result<()> {\n    for (item, is_dir) in read_dir_items(fs, source).await? {\n        let Ok(item_relative_path) = item.strip_prefix(source) else {\n            continue;\n        };\n        let target_item = if item_relative_path == Path::new(\"\") {\n            target.to_path_buf()\n        } else {\n            target.join(item_relative_path)","sourceCodeStart":3476,"sourceCodeEnd":3512,"githubUrl":"https://github.com/zed-industries/zed/blob/9d272b036335401f339d024ea94968fd51016c40/crates/fs/src/fs.rs#L3476-L3512","documentation":"Inside the directory-copy loop (copy with entries), each item is materialized at target/<relative_path>; if that target item exists, overwrite=false, and ignore_if_exists=false, the copy aborts with the offending path. Directories are removed-then-recreated only after this guard passes, so an existing directory is an error, not something the code quietly merges.","triggerScenarios":"fs copy of a directory tree (copy_entries/copy with CopyOptions { overwrite: false, ignore_if_exists: false }) where any file or subdirectory already exists at the destination.","commonSituations":"Re-extracting or re-copying an archive/project into a non-empty destination, installing extensions/themes over a previous version, or concurrent writers producing the same nested path.","solutions":["Pass overwrite: true in the CopyOptions for the tree copy when replacing is intended","Pass ignore_if_exists: true to skip colliding items and keep the rest","Clear the destination subtree first if a clean copy is required"],"exampleFix":"// before\nfs.copy(&source_dir, &target_dir, CopyOptions { overwrite: false, ignore_if_exists: false }).await?; // \"{target_item:?} already exists\"\n\n// after\nfs.copy(&source_dir, &target_dir, CopyOptions { overwrite: true, ignore_if_exists: false }).await?;","handlingStrategy":"validation","validationCode":"if !options.overwrite && fs.metadata(&target).await.is_ok() {\n    // pre-scan destination and decide skip vs replace before the per-item bail\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = fs.copy(&source_dir, &target_dir, options).await {\n    if e.to_string().contains(\"already exists\") { /* rerun with overwrite:true */ } else { return Err(e); }\n}","preventionTips":["Pass overwrite:true for re-install/re-extract flows","Copy into a fresh staging directory and swap, so partial collisions never abort mid-tree"],"tags":["filesystem","copy","directory","file-exists","zed-fs"],"backgroundTag":"file-already-exists","analyzedSha":"9d272b036335401f339d024ea94968fd51016c40","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}