nikivdev/code · error
failed to persist {}: {}
Error message
failed to persist {}: {} What it means
This error comes from temp.persist(path) in a stage-write-persist helper in flow_config.rs: a NamedTempFile is written then atomically renamed onto the destination path, and the persist step failed. persist fails when the rename(2) syscall fails, typically because the temp file and destination are on different filesystems or the destination is locked/blocked.
Source
Thrown at src/flow_config.rs:788
}
Ok(artifacts)
}
fn write_atomic(path: &Path, content: &str) -> Result<()> {
if let Some(parent) = path.parent() {
ensure_dir(parent)?;
}
let dir = path
.parent()
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("."));
let mut temp = NamedTempFile::new_in(&dir)
.with_context(|| format!("failed to stage {}", path.display()))?;
temp.write_all(content.as_bytes())
.with_context(|| format!("failed to write {}", path.display()))?;
temp.persist(path)
.map_err(|err| anyhow::anyhow!("failed to persist {}: {}", path.display(), err.error))?;
Ok(())
}
fn prune_empty_generated_parents(mut current: Option<&Path>, root: &Path) -> Result<()> {
while let Some(path) = current {
if path == root || !path.starts_with(root) || !path.exists() {
break;
}
let is_empty = fs::read_dir(path)
.with_context(|| format!("failed to read {}", path.display()))?
.next()
.is_none();
if !is_empty {
break;
}
fs::remove_dir(path).with_context(|| format!("failed to remove {}", path.display()))?;
current = path.parent();
}View on GitHub (pinned to a747e741ae)
Solutions
- Ensure the destination path is a file path, not an existing directory
- Configure the temp file to be created in the same directory as the destination (the code already tries PathBuf::from(".") / path parent — verify the parent resolves correctly)
- Close processes holding the destination file open (editors, sync tools) and retry
- Check write/execute permissions on the destination directory
Example fix
// before
let dir = path.parent().map(Path::to_path_buf).unwrap_or_else(|| PathBuf::from("."));
let mut temp = NamedTempFile::new_in(&dir)?;
// after
let dir = path.parent().map(Path::to_path_buf).unwrap_or_else(|| PathBuf::from("."));
fs::create_dir_all(&dir)?; // ensure parent exists on same fs
let mut temp = NamedTempFile::new_in(&dir)?; Defensive patterns
Strategy: try-catch
Validate before calling
let p = std::path::Path::new(dest);
if p.is_dir() { anyhow::bail!("{} is a directory, expected a file path", p.display()); }
if let Some(parent) = p.parent() { std::fs::create_dir_all(parent)?; } Try / catch
if let Err(e) = write_config_atomic(path, content) {
if e.to_string().contains("failed to persist") {
// fall back to non-atomic write
std::fs::write(path, content)?;
} else { return Err(e); }
} Prevention
- Always persist temp files into the destination's own directory (same filesystem)
- Never point config paths at directories
- Close editors/sync tools that hold locks on generated files
When it happens
Trigger: Calling the persist helper (used when writing flow config/generated files) where temp.persist() cannot rename the temp file onto `path` — e.g. path is on another mount, target is a directory, or the OS refuses the replace.
Common situations: Config path pointing at a directory, cross-device temp dir vs config dir, destination opened by another process (Windows file locking), or permissions changed between staging and persist.
Related errors
- jj git export retry loop should always return
- fzf not found on PATH – install it to use fuzzy selection.
- moon build output directory missing: {}
- Refusing to overwrite {}
- Refusing to overwrite {}
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/fccb87b845a87a3a.
Report an issue: GitHub.