CLI freezes on FocusGained in Zellij while requerying terminal palette

Resolved 💬 4 comments Opened Jul 14, 2026 by gretzke Closed Aug 4, 2026

What version of Codex CLI is running?

codex-cli 0.144.3 (also reproduced on 0.144.1)

codex doctor --json reports 0.144.4 is now available. The same synchronous focus-query path is still present on main at commit b24aa20107f365a1d0f06de9e0b28df5c516c7dd.

What subscription do you have?

ChatGPT subscription. The failure occurs in terminal focus handling before any model-dependent work.

Which model were you using?

gpt-5.6-sol (not relevant to the failure)

What platform is your computer?

Darwin 25.5.0 arm64 arm
macOS 26.5.1

What terminal emulator and version are you using?

  • Ghostty 1.3.1
  • Zellij 0.44.3

Codex doctor report

Relevant redacted fields from codex doctor --json:

{
  "overallStatus": "warning",
  "codexVersion": "0.144.3",
  "auth": {
    "mode": "chatgpt",
    "status": "ok"
  },
  "config": {
    "model": "gpt-5.6-sol",
    "modelProvider": "openai",
    "status": "ok"
  },
  "installation": {
    "installMethod": "npm",
    "platform": "macos-aarch64",
    "status": "ok"
  },
  "system": {
    "os": "Mac OS 26.5.1 [64-bit]",
    "locale": "C.UTF-8"
  },
  "terminal": {
    "TERM_PROGRAM": "ghostty",
    "terminal": "Ghostty",
    "terminalVersion": "1.3.1",
    "multiplexer": "zellij 0.44.3",
    "COLORTERM": "truecolor"
  }
}

The only doctor warning concerns old rollout files and is unrelated to terminal input.

What issue are you seeing?

After a FocusGained event, the Codex TUI can freeze indefinitely inside Zellij. The process remains alive, but the UI stops redrawing and does not accept keyboard input.

A macOS process sample taken while frozen showed the main thread blocked under:

TuiEventStream::map_crossterm_event
  -> terminal_palette::requery_default_colors
  -> crossterm foreground/background color query
  -> terminal response read/poll

On the current source path, Event::FocusGained synchronously calls requery_default_colors() while crossterm's event stream is active. The Unix implementation performs foreground and background OSC queries without a timeout. When the expected terminal response is absent or not delivered to that reader through Zellij, focus handling never returns.

As a diagnostic, I patched the installed ARM64 requery_default_colors function to return immediately, ad-hoc re-signed the binary, and launched it in a fresh PTY. It survived three focus-loss/focus-gain cycles and continued accepting input, including /quit. This isolates the freeze to the palette requery rather than general focus handling.

What steps can reproduce the bug?

  1. Open Ghostty 1.3.1 on macOS 26.5.1.
  2. Start Zellij 0.44.3.
  3. Start Codex CLI 0.144.3 inside a project.
  4. Move focus away from Ghostty and then focus it again.
  5. Repeat the focus cycle if needed.
  6. Observe that Codex eventually stops redrawing and accepting input while the process remains alive.
  7. Sample the process with sample <pid>; the main thread is blocked in the terminal palette requery path described above.

What is the expected behavior?

Focus handling should always return promptly. Codex may refresh terminal theme colors after focus is regained, but a missing OSC response must not freeze the TUI.

Additional information

There is already a bounded terminal color probe used during startup: terminal_probe::default_colors(DEFAULT_TIMEOUT), where DEFAULT_TIMEOUT is currently 100 ms.

A narrow fix is to:

  1. pause the Unix EventBroker when handling FocusGained;
  2. refresh the palette using the existing bounded direct-TTY probe;
  3. resume the event source before returning TuiEvent::Draw.

Pausing the event broker prevents the bounded direct-TTY probe from racing crossterm's background input reader, while the timeout guarantees that focus handling cannot block indefinitely. This preserves focus-triggered theme refresh rather than removing it.

I implemented this two-file change locally along with a Unix regression test that sends FocusGained, verifies the redraw and broker restart, and then verifies that a key event is delivered by the restarted source. Validation completed successfully:

just test -p codex-tui
Summary: 3046 tests run: 3046 passed, 4 skipped

just fix -p codex-tui
just fmt

I can provide the local patch if the team would like it or invites a pull request.

View original on GitHub ↗

4 Comments

Nikola-Milovic · 1 month ago

Confirming the same behavior on Linux after a NixOS upgrade.

Environment:

  • Codex CLI: 0.144.4
  • OS: NixOS 26.05.20260712.569d578 (x86_64)
  • Kernel: Linux 6.19.10
  • Terminal: Foot 1.27.0
  • Multiplexer: Zellij 0.44.3
  • TERM=xterm-256color
  • COLORTERM=truecolor

Symptoms match this report: Codex works normally and then the TUI stops redrawing and accepting keyboard input while the process remains alive. Closing the terminal and starting Codex again with resume allows the session to continue.

This began immediately after upgrading my system. The relevant package changes were:

  • Zellij: 0.43.1 → 0.44.3
  • Foot: 1.25.0 → 1.27.0
  • NixOS: 25.11 → 26.05

The same Codex 0.144.4 package was already present before the NixOS switch, so the Zellij upgrade—especially the exact match with 0.44.3 in this report—looks like the significant change. All affected Codex processes were running inside Zellij.

lbmeng · 1 month ago

There is a related, but apparently distinct, Zellij 0.44.3 issue: https://github.com/zellij-org/zellij/issues/5365, with a proposed fix in https://github.com/zellij-org/zellij/pull/5375.

In the captured detach/reattach failure, delayed replies to Zellij's client startup probes overlapped with Codex's OSC 10/11 palette query. Zellij could then forward an unrelated DECRPM reply (CSI ?2026;2$y) into the Codex PTY. This left crossterm's input parser holding a CSI prefix and caused subsequent key presses to appear ignored. PR #5375 fixes this by matching forwarded host replies to the query that requested them.

This does not appear to be the same root cause as the original report here: #33037 reproduces on FocusGained without reattaching, and its process sample shows the main thread blocked inside the synchronous palette-query path. The Zellij change only fixes reply isolation and does not change Codex's FocusGained/event-reader synchronization, so a bounded Codex-side query still appears independently valuable.

I am sharing this because the outward symptom, Zellij version, and OSC 10/11 path overlap. Testing with the Zellij PR may help determine which failure mode a particular report is hitting.

mehulparmariitr · 1 month ago

Implementation update relevant to this exact FocusGained stack:

The focus commit pauses and recreates the Crossterm event source around palette refresh, replaces sequential color-query waits with the existing batched probe under one shared 100 ms deadline, and preserves cached colors on timeout/error.

The instrumented report reproduced multi-second focus blocking without Zellij, so this addresses the Codex-side synchronous stall. Zellij may still have an additional reply-isolation failure mode. Direct upstream PR creation is invitation-gated; maintainers can invite the branch or use its commits in an OpenAI-owned PR.

gretzke · 23 days ago