Windows desktop thread can stop returning local shell command results; even small local file reads hang until manually aborted

Open 💬 6 comments Opened Apr 19, 2026 by Shrek0519
💡 Likely answer: A maintainer (etraut-openai, contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

Unknown. I did not capture the exact app version before reporting because the affected thread could no longer reliably return command output.

What subscription do you have?

Unknown / not relevant to the reproduction.

What platform is your computer?

Windows desktop app. Workspace path involved was on G:\cursor project\codex.

What issue are you seeing?

A Codex Desktop thread can get into a bad state where very small local shell commands never return results to the thread.

This does not look like a normal network failure, because the affected commands were local file reads that should complete immediately, for example:

  • Get-Content -Raw .\\AGENTS.md
  • cmd /c type AGENTS.md
  • other small local inspection commands

Observed behavior:

  • The command appears to start but no result comes back to the thread.
  • After waiting a long time, the only visible outcome is effectively that the command had to be manually interrupted/aborted.
  • The issue persisted even after switching from parallel calls to a single minimal command.
  • read_thread_terminal also indicated that no app terminal session was attached to the thread yet.

This makes the problem look more like a thread/session/tool-return-path failure than a bad shell command.

What steps can reproduce the bug?

I cannot guarantee a 100% minimal repro yet, but this was the sequence that triggered it for me:

  1. Open Codex Desktop on Windows.
  2. Work in a local workspace.
  3. Run a few tool/shell commands in the thread, including at least one interrupted or aborted command.
  4. Continue trying small local shell commands in the same thread.
  5. Eventually even trivial local commands such as reading a small local file stop returning output.

What is the expected behavior?

Small local shell commands should return quickly in the thread, especially simple local file reads that do not require network access.

If a thread loses its terminal/session attachment, the app should surface a clear error and recover cleanly instead of appearing to hang.

Additional information

A few reasons this seems worth triaging as a desktop-thread/session issue:

  • It affected local file reads, so it does not look like an internet connectivity issue.
  • It still happened after simplifying the command down to a single-file read.
  • It happened within a specific thread/session rather than looking like a deterministic command syntax problem.
  • It may be related to thread state becoming dirty after multiple manual aborts/interrupted commands.

I also considered whether this could be a Codex CLI conflict, but from the observed behavior it looks more like a desktop app thread/session regression or a tool result handoff issue.

If needed, I can try again in a fresh thread and provide follow-up data comparing:

  • old thread vs new thread behavior
  • after app restart vs before app restart
  • whether the problem reproduces only after several manual aborts

View original on GitHub ↗

6 Comments

Shrek0519 · 3 months ago

Additional data point from the reporter:

  • The Codex Desktop app was the latest version updated around April 16, 2026.
  • After restarting the computer, the problem went away and the app/thread behavior returned to normal.

This seems to strengthen the hypothesis that the issue may be related to thread/session state getting stuck or corrupted, rather than a permanent workspace/file problem.

etraut-openai contributor · 3 months ago

If you're able to repro, please use /feedback to upload the logs and session details, then post the thread ID here.

github-actions[bot] contributor · 3 months ago

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

  • #16970
  • #18465
  • #17326
  • #17325

Powered by Codex Action

dzammit · 2 months ago

Diagnosed and verified the root cause and fix for this issue:

This hang is caused by a concurrency deadlock in the shell execution pipeline due to back-pressure on a bounded async event channel.

When a command like Get-Content -Raw produces a massive burst of text, the read_output background task in codex-rs/core/src/exec.rs reads it in chunks and emits UI delta events via a bounded channel (stream.tx_event.send(event).await).

If the UI/agent loop cannot consume these events fast enough, the channel fills up, and the send().await call blocks the read_output task. Because the Rust stream reader is suspended, the OS process pipe buffer (~64KB on Windows) fills up, causing the child process (PowerShell) to block indefinitely trying to write to stdout. The main agent loop is then stuck waiting on child.wait(), resulting in a permanent "Working..." state.

The Fix:
Replace the blocking .await call with a non-blocking .try_send() when emitting streaming UI events (ExecCommandOutputDeltaEvent).

1 // codex-rs/core/src/exec.rs (Inside read_output)
2 // Change:
3 // let _ = stream.tx_event.send(event).await;
4 // To:
5 let _ = stream.tx_event.try_send(event);

This allows the stream reader to intentionally drop intermediate UI updates when under back-pressure, keeping the pipe drained.
The actual process output is still independently aggregated in memory without back-pressure and successfully returned at the end of the tool call.

I have compiled and verified this fix locally, and it completely resolves the hanging behavior for large file reads on Windows.
Since external PRs are by invitation only, I'm providing the fix here.
(I had raised a separate issue (https://github.com/openai/codex/issues/18983), but have closed that as it does appear to be duplicate of this one)

etraut-openai contributor · 2 months ago

@dzammit, thanks for digging into this. I don't think this is the root cause.

In current main, the stream.tx_event channel used by read_output is created with async_channel::unbounded(), so stream.tx_event.send(event).await should not block from normal channel back-pressure. Because of that, changing it to try_send() would not actually drop intermediate deltas under load in the current code; it would still enqueue them unless the receiver is closed.

dzammit · 2 months ago

Hi @etraut-openai - Apologies, you're right, thanks for checking this.

Further investigation confirmed that stream.tx_event is backed by async_channel::unbounded(), so stream.tx_event.send(event).await is not the bounded back-pressure point intially described. Changing that call to try_send() was not the right fix.

The other place that may still introduce bounded back-pressure before event delivery is rollout persistence:

  • send_event_raw persists rollout items before calling deliver_event_raw
  • persist_rollout_items calls into RolloutRecorder::record_items
  • RolloutRecorder uses a bounded Tokio mpsc::channel::<RolloutCmd>(256)
  • if record_items uses self.tx.send(...).await for high-volume output deltas, that could block before the UI event is delivered

So, the better candidate for this issue seems to be the rollout recorder queue, specifically making normal RolloutCmd::AddItems enqueueing non-blocking while keeping explicit persist / flush / shutdown operations reliable.

The earlier exec.rs change did appear to improve the repro locally but that may have just been a timing/scheduling effect. Removing a .await from the stdout-reading loop can make the reader drain output faster even on an unbounded channel, which may have resulted in avoiding the timing-sensitive hang even if it wasn't addressing the actual back-pressure point.

In any event, I'll do some of my own checks on this and update feedback/findings here.