{"record":{"id":"4fc004ff6b53bfa2","repo":"xai-org/grok-build","slug":"destination-already-exists","errorCode":null,"errorMessage":"destination already exists","messagePattern":"destination already exists","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"warning","filePath":"crates/codegen/xai-grok-shell/src/session/workflow/registry.rs","lineNumber":645,"sourceCode":"        file.write_all(bytes)?;\n        file.sync_all()?;\n        #[cfg(unix)]\n        std::fs::hard_link(&temp, target)?;\n        #[cfg(windows)]\n        atomic_rename_noreplace_windows(&temp, target)?;\n        if let Ok(dir) = std::fs::File::open(parent) {\n            let _ = dir.sync_all();\n        }\n        Ok(())\n    })();\n    let _ = std::fs::remove_file(&temp);\n    result\n}\n\n#[cfg(windows)]\nfn atomic_rename_noreplace_windows(source: &Path, target: &Path) -> io::Result<()> {\n    if target.exists() {\n        return Err(io::Error::new(\n            io::ErrorKind::AlreadyExists,\n            \"destination already exists\",\n        ));\n    }\n    std::fs::rename(source, target)\n}\n\n#[derive(Debug, Clone, serde::Serialize)]\npub(crate) struct WorkflowListing {\n    pub name: String,\n    pub description: String,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub when_to_use: Option<String>,\n    pub source: &'static str,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub path: Option<String>,\n}\n","sourceCodeStart":627,"sourceCodeEnd":663,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/session/workflow/registry.rs#L627-L663","documentation":"On Windows, atomic create-without-replace is emulated: atomic_rename_noreplace_windows first checks target.exists() and returns io::ErrorKind::AlreadyExists before renaming, so concurrent creation of the same workflow file fails fast instead of overwriting. It exists to guarantee that saving a brand-new workflow never clobbers an existing one.","triggerScenarios":"atomic_create_new on Windows when the destination workflow file already exists — i.e. saving a project workflow whose file was already created (possibly by a concurrent writer or a previous run).","commonSituations":"Two processes/threads saving the same workflow id simultaneously on Windows; retrying a save after a timeout that actually succeeded; leftover file from a previous session with the same id.","solutions":["Generate/use a fresh unique workflow id instead of reusing an existing one","Check existence first and treat AlreadyExists as \"already saved\" if content is equivalent","Use a read-modify-write or update path for existing workflows rather than create-new","On Windows race-prone environments, serialize saves through a lock or the persistence channel"],"exampleFix":"// before\nregistry.save_project_workflow(&path, &bytes)?; // Err(AlreadyExists) on Windows\n// after\nif path.exists() {\n    registry.update_project_workflow(&path, &bytes)?;\n} else {\n    registry.save_project_workflow(&path, &bytes)?;\n}","handlingStrategy":"retry","validationCode":"if cfg!(windows) && target.exists() {\n    // treat as update rather than create-new\n    return update_workflow(target, bytes);\n}","typeGuard":"fn can_create_new(target: &Path) -> bool {\n    !target.exists()\n}","tryCatchPattern":"match registry.save_project_workflow(&target, &bytes) {\n    Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {\n        // existing workflow: compare content or use update path\n        registry.update_project_workflow(&target, &bytes)?;\n    }\n    other => other?,\n}","preventionTips":["Use unique per-workflow ids (e.g. UUIDv7) to avoid collisions","Serialize concurrent saves to the same id behind a lock or single writer","On Windows, check existence and branch to update instead of create-new","Clean up stale workflow files from previous runs before re-saving"],"tags":["io","windows","race-condition","file-exists"],"backgroundTag":"file-already-exists","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}