BigPizzaV3/CodexPlusPlus · error

Runtime write verification failed

Error message

Runtime write verification failed

What it means

After `atomic_write(&target, &candidate)`, `prepare` reads the target back and verifies it now equals the candidate bytes. A mismatch means the atomic write did not take effect as observed — the filesystem lied, another writer immediately overwrote the file, or the read hit a stale/cached view. Codex++ treats this as a post-write invariant violation and fails rather than reporting success with an unpatched or corrupted runtime.

Solutions

  1. Rerun reconcile on a local filesystem; move `CODEX_HOME` off network mounts if applicable.
  2. Check for and stop other processes (codex desktop, sync/AV) that touch the plugin cache, then retry.
  3. Verify disk health/free space (`dmesg`, `df`) if failures repeat.
  4. Capture `read_regular(&target)` contents after the failure to confirm what actually landed before filing a bug.

Example fix

// before
// CODEX_HOME on NFS mount
export CODEX_HOME=/mnt/nfs/home/.codex
// after
export CODEX_HOME="$HOME/.codex"  # local disk, coherent fs semantics
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure CODEX_HOME is on a local filesystem with coherent write semantics
let meta = std::fs::metadata(codex_home)?; // reject network mounts in your launcher
if is_network_mount(&meta) { bail!("CODEX_HOME must be on a local filesystem"); }

Try / catch

match reconcile(&paths, true) {
    Err(e) if e.to_string().contains("Runtime write verification failed") => {
        // inspect what actually landed, check for external writers / fs issues
        let landed = std::fs::read(runtime_root.join(&key).join("service.mjs"))?;
        eprintln!("write not observed; {} bytes landed", landed.len());
        // move CODEX_HOME to local disk or quiesce writers, then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: `reconcile(paths, true)` completes `atomic_write` and the follow-up `read_regular(&target) != candidate`. Causes: an external process overwriting the file right after the write, network/overlay filesystem (network home dirs, some container mounts) with incoherent visibility, or full-disk conditions corrupting the write.

Common situations: Codex home on NFS/SMB or inside a VM shared folder; aggressive endpoint-protection rewriting files; another reconcile/codex update racing immediately after the write.

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/9bdf31f0d9868ef8. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-core/src/native_browser.rs:454

            modified_nanos: modified.subsec_nanos(),
        };
        // Durable original and journal precede any runtime write.
        atomic_write(&journal_path, &serde_json::to_vec(&journal)?)?;
    }
    let (journal, original, candidate) = recovery_material(paths, key, contract)?;
    if current == candidate {
        return Ok(());
    }
    ensure!(
        current == original && sha(&current) == journal.original_sha,
        "Runtime changed outside Codex++; refusing to overwrite"
    );
    ensure!(
        read_regular(&target, MAX_SERVICE)? == current,
        "Concurrent runtime change"
    );
    atomic_write(&target, &candidate)?;
    ensure!(
        read_regular(&target, MAX_SERVICE)? == candidate,
        "Runtime write verification failed"
    );
    Ok(())
}

fn recovery_material(
    paths: &BrowserPaths,
    key: &str,
    contract: &RuntimeContract,
) -> Result<(Journal, Vec<u8>, Vec<u8>)> {
    ensure!(key_valid(key), "Invalid recovery key");
    let dir = paths.state_root.join(key);
    let journal: Journal = serde_json::from_slice(&read_regular(&dir.join("journal.json"), 4096)?)?;
    let original = read_regular(&dir.join("original.mjs"), MAX_SERVICE)?;
    ensure!(
        journal.candidate_sha.len() == 64
            && journal.candidate_sha.bytes().all(|b| b.is_ascii_hexdigit()),

View on GitHub (pinned to b1ed92e5e4)