BigPizzaV3/CodexPlusPlus · error
.codex-global-state.json changed while restoring sidebar…
Error message
.codex-global-state.json changed while restoring sidebar state
What it means
After restoring missing sidebar entries into the in-memory state, the code re-reads .codex-global-state.json and aborts if the file's bytes changed since it was originally read, to avoid a lost-update: writing back would clobber concurrent modifications. The error signals such a concurrent change was detected.
Solutions
- Close other Codex/manager instances and rerun the restore so the file is stable during the operation
- Retry the restore — the check is a lost-update guard, so a rerun on a quiet system will succeed
- If it keeps failing, back up the current file, remove stale state, and let a fresh sync rebuild sidebar state
Example fix
// before
restore_sidebar_state(&path, ...)?; // may hit concurrent write
// after
loop {
match restore_sidebar_state(&path, ...) {
Ok(n) => { break; }
Err(e) if e.to_string().contains("changed while restoring") => {
std::thread::sleep(Duration::from_millis(500)); // retry after quiescing writers
}
Err(e) => return Err(e),
}
} Defensive patterns
Strategy: retry
Validate before calling
let before = std::fs::read(&path)?;
// ... perform restore ...
if std::fs::read(&path)? != before {
eprintln!("file changed concurrently; retry restore");
} Try / catch
match restore_sidebar_state(&path, snapshot) {
Err(e) if e.to_string().contains("changed while restoring") => {
std::thread::sleep(Duration::from_millis(500));
restore_sidebar_state(&path, snapshot)?; // retry once file is stable
}
other => other?,
} Prevention
- Ensure only one process writes .codex-global-state.json at a time (single-instance lock)
- Quiesce Codex CLI/manager before running restore
- Back up the state file before restore operations
When it happens
Trigger: Calling the sidebar restore function while another process (Codex CLI, manager UI) rewrote .codex-global-state.json between the initial read and the final atomic_write.
Common situations: Two app instances running simultaneously; Codex itself persisting state while restore is in progress; sync/backup tools touching the file during restore.
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
- bridge context lock poisoned
- 当前对话尚未读取完成,请稍后重试
- .codex-global-state.json changed while deleting thread
- Concurrent adapter upgrade
- Concurrent recovery change
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/e541c7873296c05d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-data/src/provider_sync.rs:2896
}
if let Some(entries) = global.get("atom_entries").and_then(Value::as_object) {
let atom = root
.entry("electron-persisted-atom-state")
.or_insert_with(|| Value::Object(Map::new()));
if let Some(atom) = atom.as_object_mut() {
for (key, value) in entries {
if !atom.contains_key(key) {
atom.insert(key.clone(), value.clone());
restored += 1;
}
}
}
}
if restored == 0 {
return Ok(0);
}
if path.exists() && fs::read(&path)? != original_bytes {
anyhow::bail!(".codex-global-state.json changed while restoring sidebar state");
}
codex_plus_core::settings::atomic_write(&path, serde_json::to_string_pretty(&state)?.as_bytes())?;
Ok(restored)
}
fn restore_missing_map_entries(root: &mut Map<String, Value>, maps: &Map<String, Value>) -> usize {
let mut restored = 0usize;
for (key, entries) in maps {
let value = root
.entry(key.clone())
.or_insert_with(|| Value::Object(Map::new()));
if let (Some(target), Some(entries)) = (value.as_object_mut(), entries.as_object()) {
for (entry_key, entry_value) in entries {
if !target.contains_key(entry_key) {
target.insert(entry_key.clone(), entry_value.clone());
restored += 1;
}
}View on GitHub (pinned to b1ed92e5e4)