[Bug]: Codex shadow home check disables provider when Codex rewrites a linked file (cloud-config-bundle-cache.json)#26811

opened6d agobyLlukelabonte

Version: T3 Code (Nightly) 0.1.4-nightly.20261029.3853, macOS

What happened

After updating to this nightly, both of my Codex providers that use a shadow home (one per account) went to Disabled with this error:

1Driver 'codex' failed to create instance: Cannot create Codex shadow home entry
2'cloud-config-bundle-cache.json' because '~/.codex-account/<account>/cloud-config-bundle-cache.json'
3already exists and is not a symlink.

The other account hit the same error for config.toml. Both worked fine on the previous nightly.

Cause

From what I can tell, the new ensureSymlink in CodexHomeLayout.ts throws CodexShadowHomeEntryConflictError for any shared entry that's a real file in the shadow home, unless it's in PRIVATE_ENTRY_NAMES, SHADOW_LOCAL_ENTRY_NAMES, or REPLACEABLE_SHARED_RUNTIME_ENTRIES. One stale file disables the whole provider.

This is related to #5817 (same check), but the trigger is different. That one is about new entries Codex adds later. Here the shadow entry starts out as a correct symlink, and Codex replaces it.

The catch is that Codex creates these files itself. It writes files like config.toml and cloud-config-bundle-cache.json atomically (write temp, then rename), and the rename replaces the symlink with a real file.

Repro

  1. Set up a Codex provider with a shadow home path (for example ~/.codex-account/work).
  2. Replace cloud-config-bundle-cache.json in the shadow home with a symlink to ~/.codex/cloud-config-bundle-cache.json.
  3. Start the provider. It's detected, and Codex refreshes the cloud config bundle. The symlink is now a real file again (for me it happened about a minute after I created it).
  4. Restart T3 Code or recheck providers. The provider is Disabled with the error above.

Re-linking by hand doesn't stick. The cache expires after an hour, so Codex keeps rewriting it.

Suggested fix

  • Add cloud-config-bundle-cache.json to PRIVATE_ENTRY_NAMES. It's tied to a specific ChatGPT account and workspace, so it probably shouldn't be shared between accounts anyway.
  • For other shared entries (like config.toml), I think a warning, or re-linking when the contents match, would be better than disabling the provider. Even if a strict check is preferred, the error could suggest a fix.

Let me know if more info would help.

Synced from GitHub

Another file that hits this: .codex-global-state.json.

Setup: T3 Code (Nightly) 0.1.7-nightly.20261102.4093, Linux (Arch), codex-cli 0.166.0, a second Codex instance with a T3-managed shadow home.

What happened: the provider went to Disabled with:

1Driver 'codex' failed to create instance: Cannot create Codex shadow home entry '.codex-global-state.json'
2because '~/.t3/userdata/providers/codex/<id>/shadow/.codex-global-state.json' already exists and is not a symlink.

Codex saves this file by writing ..codex-global-state.json.tmp-<ms>-<uuid> and renaming it over the path, so the rename replaced the link with a regular file. .codex-global-state.json.bak was replaced the same way. The shadow copy was newer than the shared one and had every key the shared copy had, plus 12 more entries under electron-persisted-atom-state.

On #23472: as I read it, that PR keeps the provider enabled here, but the shadow home then keeps its own .codex-global-state.json for good. So after the first save, this file quietly stops being shared between accounts. Two options that avoid both the failure and the silent fork:

  • If the file is meant to be shared: reconcile instead of failing. Keep the newer copy in the shared home, back up the other one, and restore the link. That gives the same result as a working link (last writer wins).
  • If it's meant to be per-account: add it to PRIVATE_ENTRY_NAMES, like models_cache.json, so that's explicit.

Workaround in the meantime: I'm running a small inotify watcher that does the reconcile-and-relink step for regular files that exist in both homes. It skips SQLite files and directories. Happy to share it if useful.