Desktop: config.toml zero-filled to NUL bytes after ungraceful shutdown — non-atomic write on Windows loses entire file content
Summary
Codex Desktop on Windows writes ~/.codex/config.toml non-atomically and without FlushFileBuffers. If the OS loses power (or is force-rebooted) between the moment Codex's write() returns and the moment NTFS flushes the dirty page cache to disk, NTFS commits the file's new size to the directory metadata but never writes the data clusters. Per the file-system's zero-fill-on-read security policy, the file then reads as uniform 0x00 bytes from byte 0 to EOF, blowing away every user customization (plugins, MCP servers, sandbox mode, model settings, trusted projects).
On next launch Codex bails with:
failed to load configuration: C:\Users\<user>\.codex\config.toml:1:<size+1>: key with no value, expected `=`
because the TOML parser walks N NUL bytes as one runaway bare key and hits EOF without finding =.
Reproduction
- On Windows 10/11, launch Codex Desktop and let it write
config.toml(any settings change, plugin install, or[projects.*]trust prompt will do). - Within ~30s of the write — before Windows' lazy writeback flushes the page cache — cut power (or hold the power button until the machine shuts down hard).
- Boot back up, launch Codex Desktop.
- Expected: previous config loads, or Codex falls back to defaults cleanly.
- Actual:
~/.codex/config.tomlisNbytes of0x00. Codex refuses to start with the parse error above. The "Use backup sandbox" button doesn't fix it because that only swaps sandbox mode — the parser fails before sandbox setup even runs.
Forensic evidence from one occurrence
File: C:\Users\<user>\.codex\config.toml
Size: 4183 bytes
First 16 bytes: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Last 16 bytes: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
LF count: 0
CR count: 0
NUL count: 4183
Unique byte values across whole file: { 0x00 }
File mtime matched the user's last Codex action ~5 minutes before the power loss. Three sibling files in .codex/ (AGENTS.md, auth.json, chrome-native-hosts-v2.json) were untouched by the same crash window because they hadn't been re-written that session — they survived intact.
Root cause
This is the classic ext4 zero-after-crash pattern, just on NTFS. Codex's persistence path appears to be a straight open(path, O_TRUNC) → write() → close(), without:
- writing to a temp file (
config.toml.tmp), FlushFileBuffers(handle)to force the dirty cache to disk,MoveFileEx(tmp, dst, MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING)for atomic replace.
Without these, the durability guarantee Codex appears to depend on doesn't exist on Windows.
Suggested fix
Adopt write-temp-then-rename atomic semantics for config.toml (and any other crash-critical files in ~/.codex/, e.g. auth.json, .codex-global-state.json, chrome-native-hosts-v2.json):
// pseudocode
let tmp = path.with_extension("toml.tmp");
{
let mut f = File::create(&tmp)?;
f.write_all(contents.as_bytes())?;
f.sync_all()?; // FlushFileBuffers under the hood on Windows
}
// On Windows: MoveFileExW(tmp, path, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)
// On POSIX: rename(tmp, path)
fs::rename(tmp, path)?;
This makes the worst possible crash leave either the old intact file or the new intact file on disk — never a zero-filled phantom.
Secondary observation (separate, possibly related)
When a user hits this and clicks "Use backup sandbox", Codex tries to set up the elevated admin sandbox, which on some machines fails with "Couldn't set up admin sandbox" (see #14808, #23249). That makes the "Use backup sandbox" recovery path effectively a dead end for affected users — they have to fix the config file manually before Codex will boot at all.
Workaround for currently-affected users
- Move the zeroed file aside:
Move-Item ~/.codex/config.toml ~/.codex/config.toml.corrupt - If you've ever shared a session that included a
Get-Content config.tomlagent call, your old config may be recoverable from the JSONL rollout file. - Otherwise: start Codex with an empty config, set
[windows] sandbox = "unelevated"if you hit the secondary sandbox bug, re-trust your projects on demand.
Environment
- OS: Windows 11 Pro 10.0.26200
- Codex Desktop: latest as of 2026-06-04
- Reproduction trigger: power loss during a Codex session
3 Comments
My codex app just crashed and I lost ALL of my projects and conversations.
Additional occurrence on Windows after an abrupt restart / forced reboot, on a newer Codex Desktop build.
Environment:
User-visible symptom:
Logs contained repeated entries:
Forensic evidence:
So both the manually saved broken config and the adjacent backup TOML were fully zero-filled, not merely syntactically malformed.
Impact in this occurrence:
{"schemaVersion":1,"projects":[]}.state_5.sqlite/list_threads; several private local workspaces were visible there, so session data was not fully lost.codex mcp listreturnedNo MCP servers configured yet.Recovery performed locally:
%USERPROFILE%\.codex\config.tomlfrom surviving active defaults, session history, project-local.codex/config.tomlfiles, VS Codemcp.json, and old rollout evidence.[projects.*]entries usingstate_5.sqlitethreadcwdvalues.tomllib.codex mcp listafter repair:This reinforces the original report: config writes need crash-safe atomic temp-file + flush + rename semantics on Windows, and Codex should preserve a last-known-good config or auto-recover from project/thread state instead of falling back to defaults and losing MCP/project settings after a single corrupted TOML write.
Related broader state-loss issue: #26990
Additional occurrence on Windows, with a newer Desktop build and no known power loss or forced shutdown.
Environment / timing:
The app appeared normal the previous day. After the update/relaunch, the initial user-visible symptom was that all projects disappeared from the sidebar.
Recovery behavior was unusual:
Forensic evidence then showed:
The app-server error was:
An adjacent backup of the config was also uniformly NUL-filled, so it had no recovery value.
The project/conversation data itself was not deleted:
state_5.sqlitestill contained the local threads and their workspacecwdvalues..codex-global-state.jsonhad collapsed to a one-project state.2026-07-13-local-projectsand2026-07-14-repair-metadata-local-projects), so restarting alone did not rebuild the sidebar.Local recovery required fully exiting Codex, replacing the invalid config, and reconstructing the project/global-state JSON from surviving pre-migration state plus
state_5.sqlite. Both the primary global-state file and its adjacent backup had to be repaired before restart. After that, all 8 projects and their conversations returned and could be opened.This looks like the same zero-filled
config.tomlfailure described in this issue, combined with the broader project/sidebar state loss tracked in #26990. The important difference is that this occurrence was correlated with a Desktop update/relaunch rather than a known power-loss event. The “Finish Windows setup” prompt also appears to be a misleading downstream symptom: invalid config/default fallback prevented normal Desktop settings and Windows sandbox initialization while the durable thread data remained present.No raw logs, full config, project names, prompts, tokens, or private paths are included here. I can provide specific redacted diagnostics if maintainers identify the fields needed.