BigPizzaV3/CodexPlusPlus · error
Candidate backup conflict
Error message
Candidate backup conflict
What it means
In `prepare`, the transformed candidate is stored as `state_root/<key>/candidate-<sha>.mjs`. If that file already exists, its content must equal the freshly computed candidate; a hash-named file with mismatching content means the candidate cache is corrupt or the hash naming invariant was violated (content no longer matches its own sha name). Codex++ aborts instead of silently reusing or overwriting a bad candidate.
Solutions
- Delete the corrupt `candidate-<sha>.mjs` file and rerun reconcile so it is rewritten from the transform output.
- Reset the entire `state_root/<key>` directory and rerun reconcile.
- Exclude the Codex++ state directory from file-sync tools that can rewrite files in place.
- Verify the file's sha256 actually differs from its filename; if it matches, the transform is non-deterministic — check `control.json`.
Example fix
// before (shell) # editing the candidate file by hand vim ~/.codex/plugins/state/<key>/candidate-<sha>.mjs // after # never edit; delete and let reconcile regenerate rm ~/.codex/plugins/state/<key>/candidate-<sha>.mjs
Defensive patterns
Strategy: validation
Validate before calling
let candidate_path = state_root.join(key).join(format!("candidate-{}.mjs", expected_sha));
if candidate_path.exists() {
let on_disk = std::fs::read(&candidate_path)?;
if sha256(&on_disk) != expected_sha { /* corrupt: delete the candidate file before reconcile */ }
} Try / catch
match reconcile(&paths, true) {
Err(e) if e.to_string().contains("Candidate backup conflict") => {
for entry in std::fs::read_dir(state_root.join(&key))?
.filter_map(Result::ok)
.filter(|e| e.file_name().to_string_lossy().starts_with("candidate-"))
{ let _ = std::fs::remove_file(entry.path()); }
reconcile(&paths, true)?;
}
other => other?,
} Prevention
- Never manually edit files under the state root
- Verify candidate files hash to their filename if inspecting state
- Exclude state dirs from cloud-sync/backup restore tools
- Treat state_root as opaque, owned by Codex++
When it happens
Trigger: `reconcile(paths, true)` path where `candidate-<sha(&candidate)>.mjs` already exists in the backup dir and `read_regular(candidate_path) != candidate`. Requires the file content to diverge from the sha in its filename — e.g. partial write, manual edit, or a tool that rewrote the file in place.
Common situations: Manual editing or 'cleaning' of the state directory; a crashed/partial `write_new` followed by a disk tool recovering the wrong bytes; a shared/synced state dir (Dropbox etc.) merging conflicting versions.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Unjournaled backup conflict
- .codex-global-state.json changed while deleting thread
- 待处理的一键换肤记录无效
- External runtime change prevents recovery
- global state changed while provider sync was being written
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/48c133450ccdfe75.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/native_browser.rs:421
}
ensure!(
sha(¤t) == contract.service_sha,
"Runtime changed outside Codex++"
);
}
{
let candidate = transform(¤t, &control, contract)?;
if backup.exists() {
ensure!(
read_regular(&backup, MAX_SERVICE)? == current,
"Unjournaled backup conflict"
);
} else {
write_new(&backup, ¤t)?;
}
let candidate_path = backup_dir.join(format!("candidate-{}.mjs", sha(&candidate)));
if candidate_path.exists() {
ensure!(
read_regular(&candidate_path, MAX_SERVICE)? == candidate,
"Candidate backup conflict"
);
} else {
write_new(&candidate_path, &candidate)?;
}
let modified = fs::metadata(&target)?
.modified()?
.duration_since(UNIX_EPOCH)?;
let journal = Journal {
schema: 1,
original_sha: contract.service_sha.clone(),
candidate_sha: sha(&candidate),
modified_secs: modified.as_secs(),
modified_nanos: modified.subsec_nanos(),
};
// Durable original and journal precede any runtime write.
atomic_write(&journal_path, &serde_json::to_vec(&journal)?)?;View on GitHub (pinned to b1ed92e5e4)