Codex app freezes with no error when config.toml has duplicate tables
A malformed config.toml fails in one of two visible ways: the CLI prints 'Error loading config.toml:' with an absolute path, line and column, and refuses to start; the desktop app shows nothing useful — a blank window, a startup screen that never finishes, or a setup loop — while the real error sits in a log file under $CODEX_HOME/log. The most reported cause of the silent freeze is a duplicated TOML table, but a bad escape or a duplicate key can fail the same silent way.
Start here
Search config.toml for any table header that appears twice, and on the CLI read the path:line:column it prints.
What you see
You edited config.toml, and now the client fails in one of two visibly different ways.
- On the CLI, the failure is loud: it prints
Error loading config.toml:followed by the absolute path, line and column, then a parser message, and the CLI refuses to start. One reporter’s log readfailed to reload config: C:\Users\<user>\.codex\config.toml:150:77: missing escaped value, expectedb,e,f,n,r,`,",x,u, `U“. - On the desktop app, the failure is silent: the window opens but stays on a loading screen, goes blank, or loops through setup with no clear error in the interface. The real error sits in a log file under the Codex log directory (
$CODEX_HOME/log, which defaults to~/.codex/logand contains files such ascodex-tui.log). Reinstall, repair and reset do not help, because the broken user file survives.
The most reported cause of the silent freeze is a duplicated TOML table (most often an MCP server block added twice). But a malformed document can also fail this way without any duplicate.
What it usually means
TOML forbids defining the same table twice. This is not a Codex-specific rule; it is how the format works. A file like this is invalid:
[mcp_servers.example]
url = "https://example.invalid/mcp"
enabled = true
# The same table declared a second time - invalid TOML
[mcp_servers.example]
url = "https://example.invalid/mcp"
enabled = true
The second block does not merge with the first. The document has a duplicated key, and a parser is entitled to reject the whole file.
A duplicated key across layers can also break the app with no message: one reporter defined personality more than once (the snippet showed personality = "pragmatic") and got a completely blank window, with the log reading Failed to load config requirements and errorMessage="failed to read configuration layers: ..." (the ... is the reporter’s own elision, not literal text).
The reporter suspected that adding an MCP server through the interface may append a new block instead of updating the existing one, which would produce exactly this duplicate. That explanation is plausible but unconfirmed — treat it as a hint about where to look, not as an established cause.
Quick checks
- Did the problem start immediately after a config edit? If yes, this branch is worth checking first — it is cheap to confirm.
- On the CLI, read the printed path:line:column. The surfaced shape is
Error loading config.toml:then<absolute path>:<line>:<column>: <parser message>. Two independent reporters on different platforms produced exactly this shape. - On the desktop app, open the log, not the UI. The real error is in
$CODEX_HOME/log(defaults to~/.codex/log), not on screen. A loading screen that never finishes or a repeated setup loop is the app-side symptom. - Search the file for repeated table headers. Look for any
[section]or[section.subsection]header that appears twice. - Is there a second config file in play? A project
.codex/config.tomlor a profile file can override or duplicate a key.
Fixes, by branch
If the CLI prints a parse error with a line and column
- Back up the file first. Copy
config.tomlsomewhere safe before editing. - Open the file at the printed path in a plain-text editor that shows line numbers, and go to the reported line and column.
- Fix the quoted cause. Common cases seen in reports:
- An unclosed table — e.g.
C:\Users\user\.codex\config.toml:136:46: unclosed table, expected]“. One reporter’s root cause was a non-ASCII path whose bytes were decoded as GBK and re-encoded as UTF-8, consuming the closing quote; adding the missing'back fixed it. The reporter explicitly declined to attribute the corruption to Codex. - A bad escape in a Windows path inside a TOML double-quoted string — e.g.
missing escaped value, expectedb,e,f,n,r,`,",x,u,U``. In TOML,\d` is not a legal escape. The reporter’s broken line was a Windows path with unescaped backslashes. Two cheap workarounds: use forward slashes, or use TOML single-quoted (literal) strings, which take backslashes verbatim.
- An unclosed table — e.g.
- Save, fully quit the client, and relaunch it. Quitting matters — a cached configuration can survive a simple window close.
If the app refuses to start because of a duplicate table
- Back up the file first. Copy
config.tomlsomewhere safe before editing. You are about to change the file that controls how your client starts. - Open the file in a plain-text editor that shows line numbers, so you can see where each block begins.
- Find every repeated header. Group blocks by header name and check whether any header appears twice.
- Merge the repeated blocks into one. Keep the keys you actually want. If the two copies disagree, decide which value is correct rather than keeping both.
- Save, fully quit the app, and relaunch it. Quitting matters — a cached configuration can survive a simple window close.
- Try starting a new chat. If the freeze was caused by the duplicate, this is where it clears.
If a duplicate key blanks the window
One reporter’s blank window came from personality defined more than once across layers. The workaround that worked was renaming %USERPROFILE%\.codex\config.toml to %USERPROFILE%\.codex\config.toml.disabled — a rename, not a delete, which disables the whole user config for that run and preserves the file for inspection. Back up first, and remember this disables every user-level setting, not one key.
If the duplicate keeps coming back
- Check whether the same table is being written by two different things — for example a hand edit plus a change made through the interface.
- After each change, re-read the file and confirm there is exactly one copy of each header before restarting.
- Keep a known-good copy of the file so you can restore it in one step if a future edit goes wrong.
What not to do
- Do not delete the entire Codex configuration directory. The reported failure is a single malformed document; the fix is to correct the document, and deleting everything destroys the rest of your setup.
- Do not remove every MCP server at once. Narrow down which block is duplicated first, because otherwise you lose the information you need if a different server is involved.
- Do not disable security features to work around a parse error. They are unrelated.
- Do not run a config-validation command. No
codex config validateorcodex config checkwas found in any documentation opened, andcodex exec --strict-configappeared only once in a report whose author then retracted it and is absent from the documented global flags. There is no documented way to validate a config file. - Do not delete the session store or log directory to clear a parse error; the fix is in
config.toml.
How to tell it worked
The CLI starts and prints no config error, or the app starts, a new chat can be created, and a message can be sent. Because the desktop failure mode is silent, confirm it in the app itself (or in the log under $CODEX_HOME/log) rather than assuming the edit was enough.
If it is still failing
If the file is now valid TOML with one copy of each header and the app is still unresponsive, this guide does not apply. Revert to your backup, then look at the MCP startup path instead — a server that cannot start is a different failure with a different warning in the logs. If the CLI still prints a parse error after your fix, re-read the exact line and column it reports; the error is in that position.
Known limits of this guidance
- Evidence level: reported. One detailed public report with a minimal reproduction of the duplicate-table freeze, plus separate reports of an unclosed table (#38500), a bad Windows-path escape (#37616), and a duplicate key that blanked the window (#40855).
- The reporter’s explanation of how the duplicate appeared is a hypothesis, not a confirmed mechanism. #38500’s reporter explicitly declined to blame Codex for the corrupted entry.
- The original report was on macOS with a specific app build; the surfaced-parse-error and duplicate-key reports are Windows app builds. Four of the five config-damage reports opened are Windows — do not assume the failure class is uniform across platforms.
- The documented config-reference page contains no TOML parse-error text, no duplicate-key text and no validation command; the surfaced strings come from user reports, not documentation.
- No literal duplicate-key or duplicate-table parser message was found. The duplicate case is described by its symptom (blank window,
Failed to load config requirements); no parser string may be quoted for it. --strict-configis undocumented and its one report was retracted; it is not a validation command. No fix version can be named — #40855 is closed with no stated resolution and the rest are open.
Sources
Each source lists what it is used to support. Sources are re-read on the review schedule, not continuously.
The symptom (unresponsive app, chat cannot be sent, no user-facing error), the environment (Codex App 26.303.1606 on Darwin arm64), the minimal reproduction of a duplicated [mcp_servers.*] table, the workaround of removing the duplicate and restarting, and the reporter's hypothesis that adding MCP servers through the UI appends a block instead of updating the existing one.
The Windows double-quoted-backslash escape trap (a path with unescaped backslashes fails to parse), the verbatim log line 'failed to reload config: C:\Users<user>\.codex\config.toml:150:77: missing escaped value, expected `b`, `e`, `f`, `n`, `r`, `\`, `"`, `x`, `u`, `U`', the silent loading-screen symptom, that reinstall/repair/reset did not help because the user file survives, and the two workarounds (use forward slashes, or use TOML single-quoted literal strings).
The CLI-side error 'Error loading config.toml: C:\Users\user\.codex\config.toml:136:46: unclosed table, expected `]`', the root-cause narrative that a non-ASCII path's UTF-8 bytes were decoded as GBK and re-encoded as UTF-8 consuming the closing quote, that adding the missing `'` back fixed it, and the reporter's explicit statement that they do not attribute the corruption to Codex.
Blank window from a duplicate key across config layers (openai/codex #40855, closed)
The duplicate-key blank-window case (personality defined more than once, snippet 'personality = "pragmatic"'), the log lines 'Failed to load config requirements' and 'errorMessage="failed to read configuration layers: ..."' (the '...' is the reporter's own elision, not literal text), that reinstall/repair/reset and many other steps failed, and the reversible rename-to-'.disabled' workaround. The issue is closed with no stated resolution.
Using Codex with your ChatGPT plan — official help centre (read directly 2026-09-20)
The first-party advice to 'Restart Codex after updating your configuration' (the basis for a full restart, not just closing the window) and that 'codex doctor' exists as a diagnostics tool.
Codex config reference — log_dir (developers.openai.com, read via mirror 2026-09-20)
The documented Codex log directory: log_dir 'Directory where Codex writes log files (for example codex-tui.log); defaults to $CODEX_HOME/log.' This is where the desktop app's real config error is found, since the UI shows nothing.
Related guides
How this page is checked
- Evidence level
- Reported - based on public reports, not reproduced here
- Last reviewed
- 2026-09-20
- Content updated
- 2026-09-20
- Full version scope
- Reported on Codex App 26.303.1606 (806) on macOS, and on Windows app builds 26.803.5235.0, 26.808.x and 26.820.7780.0, among others opened. Other versions and platforms have not been documented as affected, and no fix version can be named.
- Symptoms indexed
-
- The app starts but a new chat cannot be sent
- There is no error message anywhere in the interface
- It started right after you edited config.toml
- Removing the duplicate block and restarting fixes it immediately
- On the CLI, a line such as 'Error loading config.toml: <path>:<line>:<column>: <parser message>' appears and the client will not start
- On the desktop app, the window stays on a loading screen or loops setup with no on-screen error
Reviewer note
One detailed duplicate-table report plus separate reports of an unclosed table (#38500), a Windows backslash escape (#37616) and a duplicate key that blanked the window (#40855). The CLI-vs-desktop surfacing asymmetry is documented by those reports and by the documented log_dir. No reproduction was performed here; --strict-config is undocumented and retracted, and no validation command exists.