xai-org/grok-build · warning · std::io::Error
destination already exists
Error message
destination already exists
What it means
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.
Source
Thrown at crates/codegen/xai-grok-shell/src/session/workflow/registry.rs:645
file.write_all(bytes)?;
file.sync_all()?;
#[cfg(unix)]
std::fs::hard_link(&temp, target)?;
#[cfg(windows)]
atomic_rename_noreplace_windows(&temp, target)?;
if let Ok(dir) = std::fs::File::open(parent) {
let _ = dir.sync_all();
}
Ok(())
})();
let _ = std::fs::remove_file(&temp);
result
}
#[cfg(windows)]
fn atomic_rename_noreplace_windows(source: &Path, target: &Path) -> io::Result<()> {
if target.exists() {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
"destination already exists",
));
}
std::fs::rename(source, target)
}
#[derive(Debug, Clone, serde::Serialize)]
pub(crate) struct WorkflowListing {
pub name: String,
pub description: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub when_to_use: Option<String>,
pub source: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
}
View on GitHub (pinned to bc7f02eddd)
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
Example fix
// before
registry.save_project_workflow(&path, &bytes)?; // Err(AlreadyExists) on Windows
// after
if path.exists() {
registry.update_project_workflow(&path, &bytes)?;
} else {
registry.save_project_workflow(&path, &bytes)?;
} Defensive patterns
Strategy: retry
Validate before calling
if cfg!(windows) && target.exists() {
// treat as update rather than create-new
return update_workflow(target, bytes);
} Type guard
fn can_create_new(target: &Path) -> bool {
!target.exists()
} Try / catch
match registry.save_project_workflow(&target, &bytes) {
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {
// existing workflow: compare content or use update path
registry.update_project_workflow(&target, &bytes)?;
}
other => other?,
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- workflow artifact changed during open: {}
- journal changed during open
- process scope already closed; fetch killed{}
- Failed to set working directory to {:?}: {}
- Failed to load config: {e}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/4fc004ff6b53bfa2.
Report an issue: GitHub.