BigPizzaV3/CodexPlusPlus · critical

failed to restore rollout file(s)

Error message

failed to restore {} rollout file(s): {}

What it means

restore_bulk_session_rewrites iterates applied changes in reverse and calls restore_bulk_session_rewrite for each rollout file. Any per-file failure is collected with the file path; if any failures occurred, this aggregate error is raised listing how many files failed to restore and each `path: error`.

Solutions

  1. Inspect each `path: error` entry; resolve per-file causes (unlock, fix permissions) then retry the restore
  2. For files reported as changed before rollback, restore them from an external backup — the library refuses to overwrite files it did not rewrite
  3. Re-run the full provider sync to regenerate the affected rollout files from source data
  4. Check disk space and AV/indexer interference if many files failed at once
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check each planned path for writability
let bad: Vec<_> = plans.iter().filter(|p| metadata_writeable_failed(&p.path)).collect();
if !bad.is_empty() { return Err(format!("{} unwritable targets", bad.len())); }

Try / catch

match restore_result {
    Err(e) => {
        let msg = e.to_string();
        // msg enumerates "path: error" entries; parse and remediate per file
    }
    Ok(_) => {}
}

Prevention

When it happens

Trigger: Calling the bulk-session-rewrite rollback path (directly or via the apply-failure handler) when one or more restore_bulk_session_rewrite calls return Err — e.g. hash checks fail or atomic_write_with cannot write the pre-image back.

Common situations: Rollout files modified between rewrite and rollback (hash mismatch); files locked by another process; disk or permission failures during the restore write; multiple files failing at once after a shared root cause.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/8bf2c149108795ea. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-data/src/provider_sync.rs:3657

            writer.write_all(line_ending.as_bytes())?;
            rewritten = true;
        }
        if !rewritten {
            writer.write_all(line.as_bytes())?;
        }
    }
    Ok(format!("{:x}", hasher.finalize()))
}

fn restore_bulk_session_rewrites(changes: &[AppliedBulkSessionRewrite]) -> anyhow::Result<()> {
    let mut restore_errors = Vec::new();
    for change in changes.iter().rev() {
        if let Err(error) = restore_bulk_session_rewrite(change) {
            restore_errors.push(format!("{}: {error:#}", change.plan.path.display()));
        }
    }
    if !restore_errors.is_empty() {
        return Err(anyhow::anyhow!(
            "failed to restore {} rollout file(s): {}",
            restore_errors.len(),
            restore_errors.join("; ")
        ));
    }
    Ok(())
}

fn restore_bulk_session_rewrite(change: &AppliedBulkSessionRewrite) -> anyhow::Result<()> {
    if sha256_file(&change.plan.path)? != change.rewritten_sha256 {
        return Err(anyhow::anyhow!(
            "rollout changed before rollback: {}",
            change.plan.path.display()
        ));
    }

    codex_plus_core::settings::atomic_write_with(&change.plan.path, |file| {
        let mut writer = HashingWriter::new(BufWriter::new(file));

View on GitHub (pinned to b1ed92e5e4)