Skip to content

TUI freezes during idle long wait while session continues and completes #20601

Closed

Description

What version of Codex CLI is running?

0.128.0

What subscription do you have?

Plus

Which model were you using?

No response

What platform is your computer?

Linux

What terminal emulator and version are you using (if applicable)?

alacritty

What issue are you seeing?

The Codex TUI can freeze during a long wait when there is no token streaming or assistant chatter.
The backend session continues running and can complete, but the visible TUI stops updating.

In my case, I intentionally prompted agents to avoid filler/status chatter during long waits. With that setup, the TUI animation stopped, but the task still completed in the background.

I had a local completion hook that sends a notification when the task finishes. That notification arrived even though the TUI was frozen. The old TUI process was still alive until manually killed:

PID 27495
~/.codex/bin/codex-0.128.0
state: Sl+
tty: pts/10

After completion, the session log contained task_complete, and the completion record had notified: true.

What steps can reproduce the bug?

  1. Start or resume a Codex CLI TUI session.
  2. Run a task that waits for a long time on background work.
  3. Prompt the agents not to emit periodic filler/status text while waiting.
  4. Leave TUI animations enabled so a frozen UI is visible.
  5. Wait through an idle period with little or no token streaming.

Observed result: the TUI can freeze while the backend session continues and eventually completes.

What is the expected behavior?

The TUI should remain responsive during long idle waits, or recover/repaint once backend events arrive. If the backend task completes, the TUI should visibly reflect completion without needing a second Codex session or manual process cleanup.

Additional information

Codex CLI helped identify a likely area to inspect: the TUI appears to rely on activity from streamed rollout/items or similar backend updates to keep the interface moving during long waits.

This issue was written with the assistance of Codex CLI.

Activity

  1. added
    CLIIssues related to the Codex CLI
    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal display
    on May 1, 2026
  2. github-actions commented on May 1, 2026

    @github-actions
    Contributor

    Potential duplicates detected. Please review them and close your issue if it is a duplicate.

    Powered by Codex Action

  3. etraut-openai commented on May 2, 2026

    @etraut-openai
    Contributor

    If you're able to repro this, please /feedback and post session ID.

  4. 92645417d9e5c763259dbebc306e3e commented on May 3, 2026

    @92645417d9e5c763259dbebc306e3e
    Author

    109-tui-task-frame-heartbeat.patch
    this codex-generated patch solves the issue I mentioned for me, which has not been encountered again in 0.128.0 or 0.129.0-alpha.3

  5. handsomeZR-netizen commented on May 14, 2026

    @handsomeZR-netizen

    I investigated the Windows PowerShell Working... hang on current main.

    Environment

    • OS: Microsoft Windows NT 10.0.26200.0
    • Shell: PowerShell 7.6.1
    • Codex commit: 6d65686313 feat: make ToolExecutor an async trait (#22560)
    • Local branch: windows-pwsh-working-hang-fix
    • Codex CLI version: codex-cli 0.130.0
    • Rust toolchain in codex-rs: cargo 1.93.0, rustc 1.93.0

    Summary

    The original bounded-channel stdout-reader backpressure hypothesis no longer matches current main: core session events use an unbounded channel, app-server-client treats command output deltas as best-effort, and rollout storage does not persist ExecCommandOutputDelta.

    The most plausible remaining Working... path is in the TUI active-thread routing queue. That queue made every active-thread notification effectively lossless by spawning a waiting send task when the per-thread channel was full. A large CommandExecutionOutputDelta backlog could therefore keep TurnCompleted behind many best-effort output events, leaving the UI in Working... until the backlog drained.

    Findings

    • stdout/stderr reader path: legacy exec reads pipes in codex-rs/core/src/exec.rs; unified exec reads process output into a broadcast/output buffer in codex-rs/core/src/unified_exec/process.rs.
    • intermediate output delta path: legacy read_output emits ExecCommandOutputDelta; unified async_watcher.rs emits the same event after transcript append.
    • final output aggregation path: legacy final output is aggregated in exec result construction; unified final command end comes from the transcript and process exit status.
    • completion / exit status path: TurnCompleted clears TUI Working... through ChatWidget::handle_turn_completed_notification -> on_task_complete / finalize_turn.
    • queue classification: codex-rs/app-server-client/src/lib.rs already makes CommandExecutionOutputDelta best-effort and preserves TurnCompleted, ItemCompleted, and transcript deltas.
    • remaining gap: codex-rs/tui/src/app/thread_routing.rs did not preserve that lossless/best-effort split for the active thread queue.
    • manual PowerShell validation: a 50,000-line temp file under %TEMP%\codex-pwsh-hang-repro was read with Get-Content -Raw in about 36.5 ms; no direct PowerShell hang was observed.

    Local patch

    I applied a small local patch:

    • In codex-rs/tui/src/app/thread_routing.rs, active-thread queue overflow now drops known best-effort progress/output notifications instead of spawning waiting send tasks for them. This lets lossless events such as TurnCompleted bypass a command-output backlog.
    • In codex-rs/tui/src/app/tests.rs, I added a regression test that fills a capacity-1 active-thread queue with command output delta, queues another output delta, then queues TurnCompleted; the expected next lossless event is TurnCompleted, and Working... clears.
    • In codex-rs/app-server/src/in_process.rs, I aligned the lower-level in-process app-server must-deliver helper with app-server-client for TurnCompleted, ItemCompleted, assistant/plan/reasoning deltas, while keeping CommandExecutionOutputDelta best-effort.

    Validation

    Commands run:

    cargo test -p codex-tui output_delta_backlog_does_not_delay_turn_completed_for_active_thread
    cargo test -p codex-app-server guaranteed_delivery_helpers_cover_terminal_server_notifications
    cargo fmt
    cargo fmt --check
    

    Results:

    cargo test -p codex-tui output_delta_backlog_does_not_delay_turn_completed_for_active_thread:
    1 passed.
    cargo test -p codex-app-server guaranteed_delivery_helpers_cover_terminal_server_notifications:
    1 passed.
    cargo fmt completed.
    cargo fmt --check completed.
    

    Question

    Would maintainers prefer a PR for the TUI active-thread queue best-effort drop fix first, or should a broader follow-up also make core ExecCommandOutputDelta emission explicitly best-effort even though the current core event channel is unbounded?

  6. etraut-openai commented on May 17, 2026

    @etraut-openai
    Contributor

    I think this is addressed by #21870. If you see similar symptoms, please file a new bug report using /feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal displaybugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions