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

  1. Ensure the destination path is a file path, not an existing directory
  2. 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)
  3. Close processes holding the destination file open (editors, sync tools) and retry
  4. 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

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


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/fccb87b845a87a3a. Report an issue: GitHub.