File Access Permission Selector Stuck Loading
no-active-thread-019e70e7-04d8-7212-8f52-0c90ef5db11c
Summary
The file access permission selector button is permanently stuck in a loading/spinner state across ALL conversations. This completely blocks the chat input — no messages can be sent, no commands can be issued, no work can be done. The entire application is a $200/month paperweight right now.
My subscription is active. My disk has 13GB free. macOS permissions are correct. Code signing is valid. There is nothing wrong on my end. Through deep code analysis of the asar bundle, I've traced the issue to a deadlock in the permission mode initialization pipeline.
Impact
I cannot overstate how destructive this bug is. This is not a minor inconvenience — this is a total application failure.
I have critical production projects that are blocked from launching because Codex is completely non-functional. Every hour this persists is real money lost and real deadlines missed.
I've spent hours diagnosing this myself — extracting the asar bundle, decompiling the minified JS, tracing the permission mode state machine, analyzing Statsig feature flag initialization, reading SQLite logs, and inspecting IPC handlers — because the application gave me ZERO diagnostic information. Just a silent infinite spinner.
Reproduction
Open Codex (any workspace, any project)
Look at the file access permission selector (the dropdown/button near the chat input)
It shows a loading spinner indefinitely
Try to type and send any message → impossible, input is blocked
Switch to a different conversation → same problem
Create a new conversation → same problem
Restart Codex → same problem persists
This affects 100% of conversations, not just one.
Environment & Diagnostic Details
Config (~/.codex/config.toml)
toml
sandbox_mode = "danger-full-access"
approval_policy = "never"
approvals_reviewer = "user"
The most permissive configuration possible — yet the permission selector can't even finish loading.
Entitlements (verified via codesign -d --entitlements)
com.apple.security.app-sandbox = false ← NOT sandboxed
com.apple.security.files.user-selected.read-write = true
com.apple.security.network.client = true
com.apple.security.automation.apple-events = true
com.apple.security.cs.allow-jit = true
com.apple.security.cs.allow-unsigned-executable-memory = true
All correct. No macOS-level permission issue.
Code Signature
codesign --verify --deep --strict: PASSED
Notarization: stapled
Authority: Developer ID Application: OpenAI OpCo, LLC (2DC432GLL2)
Hardened Runtime: enabled
System State
Disk: 13GB available (NOT full)
No quarantine flags (xattr clean)
No sandbox violations in system logs
No TCC denials in unified log
All Codex processes running normally (main, GPU, renderer, app-server instances)
SIP: enabled
Gatekeeper: enabled
Running Processes (at time of failure)
/Applications/Codex.app/Contents/MacOS/Codex ← main process
/Applications/Codex.app/Contents/Resources/codex app-server ← primary app-server
/Applications/Codex.app/Contents/Resources/codex app-server --listen stdio:// ← multiple instances
/Applications/Codex.app/Contents/Frameworks/Codex Helper (Renderer) ← renderer
/Applications/Codex.app/Contents/Frameworks/Codex Helper (GPU) ← GPU process
Multiple node_repl and SkyComputerUseClient instances
Everything appears to be running — yet the UI is completely stuck.
Large Data Files (potential contributors)
644 MB ~/.codex/logs_2.sqlite
91 MB ~/.codex/logs_2.sqlite-wal
5.4 MB ~/.codex/state_5.sqlite
4.0 MB ~/.codex/state_5.sqlite-wal
66 KB ~/.codex/.codex-global-state.json
The logs_2.sqlite is 735 MB combined. If any startup or permission-loading logic queries this database synchronously, this could absolutely cause the loading hang.
What I've Already Tried
✅ Verified all macOS permissions (entitlements, code signing, notarization, TCC)
✅ Checked disk space (13GB free — not the issue)
✅ Restarted Codex
✅ Verified config.toml is set to maximum permissions
✅ Checked system logs for sandbox violations (none)
✅ Confirmed no quarantine flags
✅ Tried multiple workspaces and conversations
✅ Cleaned temp files
Root Cause (from code analysis of the asar bundle)
Through decompilation and analysis of the minified source code, I've traced the exact blocking chain:
- Submit button is blocked by isAgentModePending
In composer-EYkAbDY0.js, the submit logic calls hv() which computes:
javascript
disableSubmitForPendingPermissionsMode:
e.isAgentModePending ||
(e.agentMode !== 'read-only' && e.isWindowsSandboxRequirementPending && !e.isWindowsSandboxSetupPending)
When isAgentModePending is true, the entire chat input is blocked.
- isAgentModePending comes from use-permissions-mode-BBZBxA7Q.js
The B() (exported as usePermissionsMode) function computes:
javascript
let Z = B == null && ae == null && (h || b.isConfigDataPending);
// Z becomes isAgentModePending
So if isConfigDataPending is true, the mode is stuck pending.
- isConfigDataPending comes from ne() function
The ne() function computes:
javascript
let N = h || D || w || M;
// Where:
// D = isPending from requirements query (IPC: get-config-requirements-for-host)
// w = isPending from effective config query
// M = j && n(k ?? undefined) !== false && g === undefined
// g = statsig_default_enable_features (from shared object store)
If ANY of these remain pending, the entire permission selector stays in loading state forever.
- The statsig_default_enable_features dependency
When g === undefined (Statsig feature flags not yet loaded), AND the config requirements suggest guardian mode is available (j is true), then M stays true → isConfigDataPending stays true → isAgentModePending stays true → submit is blocked.
This creates a hard dependency on Statsig initialization for the permission selector. If Statsig fails to initialize (network issues, API changes, rate limiting, corrupted cache), the entire application becomes unusable.
- Observed state in ~/.codex/.codex-global-state.json
json
"codexCloudAccess": "enabled_needs_setup"
"agent-mode-by-host-id": { "local": "full-access" }
The codexCloudAccess: "enabled_needs_setup" state may also be contributing to the loading loop.
Why This Is Unacceptable
The permission selector blocks ALL chat input. A UI component that displays a mode dropdown should NEVER be able to make the entire application unusable.
No error, no fallback, no timeout. If Statsig or the backend config query fails, the app should fall back to config.toml settings (which are danger-full-access + approval_policy = never).
Zero diagnostic information. No console error, no log entry, no UI message. Just a silent spinner.
config.toml has sandbox_mode = "danger-full-access" and approval_policy = "never" — the local configuration is correct and should be usable as a fallback.
I wasted an entire day reverse-engineering your minified JavaScript to find this. A single error message or timeout would have prevented all of this.
What I Need
Never let the permission selector block the entire chat input. If permission state can't be resolved, show an error inline or use a default — don't freeze the entire application.
Add a timeout/fallback for isConfigDataPending. If the config requirements query or Statsig initialization doesn't complete within N seconds, fall back to config.toml settings and show a warning.
Show a clear error when the permission selector can't load. A toast, a banner, anything — not a silent infinite spinner.
Add better diagnostic logging. When isConfigDataPending remains true for more than 10 seconds, log which specific sub-condition is stuck (Statsig? Config query? Requirements query?).
Make the codexCloudAccess: "enabled_needs_setup" state actionable. If setup is needed, show a setup flow. Don't just silently block everything.
Closing
I chose Codex as my primary development tool and have invested significantly in building my workflow around it. Having it completely break with no workaround and no error message — just a silent infinite spinner — is unacceptable for a product at this price point. I expect this to be treated as a P0 blocker and resolved urgently.
Diagnostic data collected at 2026-05-29T07:00 CST (UTC+8)
3 Comments
Confirming this exact bug on macOS 26.527.60818 (bundled CLI/app-server
0.136.0-alpha.2, Apple Silicon, ChatGPT Plus), and adding a decisive test + mechanism that I think pins the root cause. Cross-refs: this is the same underlying failure as #21318 (MCP tool-discovery blocks the first turn) and the macOS cluster in #23979. @denixciao-sketch's decompilation here matches what I see end to end.Symptom
Local-mode composer: the "Full access" permission selector sits in a perpetual loading/greyed state with a ⚠ icon; the send arrow spins forever and no local message can be sent; past local thread bodies render blank. Cloud mode works fine (it routes around the local app-server). Intermittent across identical builds — it worked previously with the exact same plugins/connectors installed, then stopped without any config change on my side.
Decisive test: it is NOT user config / connectors / plugins
I stripped the install to zero enabled plugins (every
[plugins.*] enabled = false, config locked withchflags uchgso the desktop couldn't re-sync it) and relaunched. Send still spun. With nothing for the tool list to wait on, the composer is still blocked. So this is not fixable from the user side — it's in the app/app-server.Mechanism (combining @denixciao-sketch's decompilation with app-server traces)
The composer's submit is gated on
isConfigDataPending, which stays true while either:list_all_toolshasn't completed — the app-server awaits tools from every MCP server on the startup/first-turn critical path (exactly #21318). Trace fromlogs_2.sqlite:``
`list_all_tools{mcp_server_count=5}: waiting for MCP server tools while building tool list
server_name=cloudflare-api has_cached_tool_info_snapshot=false startup_complete=true
has_cached_tool_info_snapshotis the key field: when a server has a cached snapshot the list returns instantly; when it'sfalse, the app-server **waits for a livetools/list** — and a slow/unauthenticated/unreachable server (e.g. a connector whose OAuth token has since expired) hangs the whole list until the 31s timeout. **This explains the intermittency and "it worked before":** when the snapshots were warm / tokens valid,list_all_tools` returned fast; once a snapshot is cold and that server doesn't answer, it hangs.statsig_default_enable_features === undefinedwith guardian mode available keepsisConfigDataPendingtrue (@denixciao-sketch's chain). My~/.codex/.codex-global-state.jsonhas 0 statsig keys cached. Clearing the statsig plugin cache doesn't help (the value comes from the live SDK init, not a file).guardian_approvalis server-pushed and ignoresfeatures.guardian_approval = falsein config — so there is no user override for this branch either.Even the hardcoded
openai-bundledmarketplace (browser/chrome/computer-use/latex) is registered via the node_repl sidecar on every launch regardless of plugin state, and itsmarketplace/addtimes out the same way:node_repl itself is healthy — the fault is the app-server driving it
Driving the bundled
node_repldirectly over stdio, it answersinitializein <1s and executes a realjstool call (spawning its sandboxed Node kernel) in ~0.25s, returning valid results — both sandboxed and with--disable-sandbox. When the app-server spawns it, the process sits parked intokio::parkwaiting for MCP traffic and is torn down ~3s later. So node_repl is fine; the app-server's sidecar/tool-discovery lifecycle is where it breaks.The fix that would actually resolve this (same as @denixciao-sketch + #21318)
isConfigDataPendingcan't resolve within N seconds, fall back toconfig.toml(mine is alreadysandbox_mode = "danger-full-access",approval_policy = "never") and let the user send. A silent infinite spinner with no error/timeout is the core defect.required = trueservers should ever block startup/first turn.isConfigDataPendingstays true >10s (which sub-condition is stuck: requirements query / Statsig / a specific MCP server).Happy to provide a
RUST_LOG=traceapp-server log slice from a failing launch, the zero-plugin-locked-config repro, thelsof/sampleof the parked node_repl, or the node_repl stdio handshake repro. Also tracked via OpenAI support case 09438125.Update: still fully broken on
26.601.20914(build 3497) — the latest auto-update as of 2026-06-02 (macOS, Apple Silicon). I updated specifically to test whether this was addressed; it is not. The failure is byte-for-byte identical to26.527.60818and26.519.31651before it.App-server log, one session on 26.601:
marketplace/add→Timed out waiting for MCP response to marketplace/add(×14),bundled_plugins_marketplace_add_failedformarketplaceName=openai-bundledexperimentalFeature/list→ timed out (this is the call the composer's send path waits on: "Failed to check workspace dependencies feature for developer instructions")config/read,configRequirements/read,collaborationMode/list→ succeed in 5–25ms only when plugins + the node_repl-dependent[features](memories/chronicle/goals) are disabled (which makes the app logreconcile_skipped_features_unavailableand skip the hanging reconcile). With them enabled,config/readtimes out and the "Full access" chip spins forever.Unable to send message / Loading…and never reaches the backend, in both a new chat and an existing local thread.Isolation done this round: from a completely clean slate — killed 27 lingering Codex processes including an orphaned
openai-bundled/chromeextension-host parented to a dead app instance (these survive normal relaunch; the new launch immediately respawns one) —marketplace/addstill times out. So it is not stale state or orphaned helpers. The bundled marketplace MCP handshake itself does not complete; the sidecar that should answermarketplace/add/experimentalFeature/listis gone seconds after launch, whilenode_replis provably healthy when driven directly over stdio (initialize<1s, a realjstool call ~0.25s).Net: the composer's send is hard-gated on MCP calls (
experimentalFeature/list,marketplace/add) that depend on a bundled sidecar that never answers — with no timeout and no fallback, so it spins indefinitely. The CLI (codex exec/TUI) sends fine on the same build because it bypasses this path.The fix, restated (matches @denixciao-sketch + #21318):
marketplace/addorexperimentalFeature/listblock the composer/first turn — make optional MCP startup non-blocking and incremental.config.tomlwhenisConfigDataPendingcan't resolve within N seconds, instead of an infinite silent spinner.Also tracked via OpenAI support case 09438125. Happy to provide the full
RUST_LOG=traceslice, the clean-slate repro, or the orphaned-extension-hostpscapture.Workaround found — and it pinpoints the exact culprit. On
26.601.20914I traced the composer-send block to the bundled-marketplace handshake. The local app-server sidecar startup andmarketplace/addhang specifically on the heavy bundled plugins (browser,chrome,computer-use); the lightweightlatexplugin adds instantly. The runtime marketplace is (re)written on startup and on every window focus withpluginCount=4 ["browser","chrome","computer-use","latex"], andmarketplace/addthen times out (observed 14×/session) — which blocksthread/start, so the composer can never dispatch.Disabling just those bundled features via the CLI:
drops the runtime marketplace to
["latex"], after whichmarketplace/addsucceeds andconfig/read,configRequirements/read,thread/start, andexperimentalFeature/listall return in milliseconds (0 timeouts across a full session). The "Full access" selector settles and local send works end-to-end — message dispatches, a new conversation is created, and the agent executes workspace tools. Connector/MCP plugins can stay fully enabled — it is specifically the three bundled browser/chrome/computer-use plugins' MCP handshake that exceeds the (too-aggressive) catalog startup timeout.This confirms the root cause discussed above: the composer is hard-gated on bundled-marketplace tool-discovery with no timeout and no fallback, and a single slow bundled plugin stalls the whole catalog. Requested fix stands:
isConfigDataPendingcan't resolve in a few seconds, instead of an infinite silent spinner.marketplace/addtimeouts sobrowser/chrome/computer-usefailing doesn't blocklatexor the send path.Repro/environment: macOS 26.5.1, Apple M1 Ultra, Codex Desktop 26.601.20914 (app-server 0.136.0-alpha.2). Tracked in OpenAI support case 09438125.