Repository navigation
TUI can get stuck with 'Messages to be submitted after next tool call' when sending during active output #15842
Description
What version of Codex CLI is running?
codex-cli 0.116.0
What subscription do you have?
ChatGPT Pro
Which model were you using?
GPT-5.4
What platform is your computer?
Linux 6.6.87.2-microsoft-standard-WSL2 x86_64 x86_64
What terminal emulator and version are you using (if applicable)?
tmux 3.4
What issue are you seeing?
When the model is still outputting and I press Enter to send a new message immediately (not queueing a later draft manually, but trying to submit right away), the TUI can get stuck showing:
Messages to be submitted after next tool call (press esc to interrupt and send immediately)
In the broken case:
- the current output stops
- no further tool call happens
- the pending message is never sent automatically
- the footer/status remains in the pending-steer state indefinitely
So from the user's perspective, the message is accepted into the UI, but it never actually becomes the next turn.
This looks different from normal queued follow-up behavior. The problem is specifically the "send immediately while output is still in progress" path getting stuck after the active output finishes.
What steps can reproduce the bug?
- Start a normal turn in the TUI so the model is actively streaming output.
- While output is still in progress, type a follow-up message.
- Press Enter before the current turn has fully finalized.
- Observe that the TUI shows:
Messages to be submitted after next tool call (press esc to interrupt and send immediately) - Wait for the current output to stop naturally.
Observed result:
- the message stays in the pending-steer preview
- it is not submitted automatically after output stops
- the TUI appears stuck in this state until manually interrupted or otherwise recovered
What is the expected behavior?
One of these should happen reliably:
- if the current turn is still steerable, the pending message should be consumed and become the next model request automatically
- if the current turn is already ending and can no longer accept steer input safely, the message should be converted into a normal queued follow-up and sent as the next turn after completion
- in either case, the TUI should not remain indefinitely stuck on
Messages to be submitted after next tool call
Additional information
This appears to be a turn-finalization race between TUI pending-steer state and core pending-input handling.
From local code inspection, the rough failure mode seems to be:
- TUI classifies the submission as a pending steer because
agent_turn_runningis still true - core accepts the input into active-turn
pending_input - if the input lands in the narrow window after the final
run_turn()iteration has effectively ended but before teardown is fully complete, it can miss the path that would start the next follow-up request - TUI then continues waiting for the pending steer to be cleared by the usual completion path, but that follow-up never starts, so the preview remains stuck
Relevant code paths I found while investigating:
codex-rs/tui/src/chatwidget.rscodex-rs/core/src/codex.rscodex-rs/core/src/tasks/regular.rscodex-rs/core/src/tasks/mod.rs
Potentially related issues:
- TUI: footer duplicates and “Working” status briefly disappears after interrupt + immediate resubmission #9811
- Hitting Ctrl+C once should interrupt the model and give you a chance to redirect it #1244
There is also an existing ignored/flaky core test that seems closely related to this class of behavior:
core/tests/suite/pending_input.rs->injected_user_input_triggers_follow_up_request_with_deltas
Activity
github-actions commentedon Mar 26, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
etraut-openai commentedon Mar 26, 2026
We are in the process of rewriting the TUI on top of the "app server" layer, which is used for other clients like the Codex app. The existing TUI implementation will be retired within the next week or so. It's likely that the bug you're experiencing does not existing in the new TUI implementation. You can enable it by using the
/experimentalflag and enabling the "App Server TUI" feature, then restarting the CLI.jkaunert commentedon Apr 11, 2026
I think there is a broader core-runtime bug family behind this, not just a TUI-only pending-preview problem.
I took a private fork and re-extracted a narrow runtime slice against
rust-v0.120.0that fixes turn progression when follow-up state arrives while the current stream is still winding down.The important part is not the Apple/plugin context from my fork. The important part is the generic runtime behavior:
That seems strongly aligned with the mechanism described in this issue:
I also found a related symptom in
#16339, where rejection follow-up text can arrive late enough that the model continues without the user’s intended steer.For reference, my local validation slice is:
upstream/tool-output-preemption-v12032d01a4bdcargo test -p codex-core pending_input -- --nocaptureIf useful, I can add a design-only follow-up here describing the exact receive-loop behavior change without posting code.
JiaJunDeng5930 commentedon Apr 12, 2026
Thanks. I checked the current main branch against the mechanism you described, and this does look closer to a broader core turn-progression / pending-follow-up timing family than to a purely TUI-local preview bug.
What I could confirm from the repo:
e4f1b3a65/ “Preempt mailbox mail after reasoning/commentary items” (Preempt mailbox mail after reasoning/commentary items #16725)8f705b070/ “Defer steering until after sampling the model post-compaction” ([codex] Defer steering until after sampling the model post-compaction #17163)So I think your read is directionally correct: this issue fits the same runtime handoff family, not just a stale TUI footer state.
One caveat from current main: the most direct regression test for the original “send another user message while output is still streaming” path in
core/tests/suite/pending_input.rsis still marked ignored/flaky. Therefore, while the broader runtime area has clearly been addressed, the exact original path from this issue does not yet appear to have a stable always-on regression test on main.That makes me think this issue is at least partially explained by fixes that already landed, but the original user-input-during-active-output race is still worth treating as a distinct validation target unless someone can confirm it is now covered reliably by newer tests.
fix(tui): rebuild pending-queue around turn_end hook (drop cooldown t…
fix(tui): rebuild pending-queue around turn_end hook (drop cooldown t…
fix(tui): rebuild pending-queue around turn_end hook (drop cooldown t…
fix(tui): rebuild pending-queue around turn_end hook (drop cooldown t…