What version of Codex CLI is running?
codex-cli 0.147.0
What platform is your computer?
Linux 5.15.120 x86_64 (also reproducible on other platforms — the bug is in the TUI prompt-edit/backtrack logic, not platform-specific)
What issue are you seeing?
When editing an earlier prompt (Esc-Esc backtrack → select a prompt → Enter), the TUI forks the thread before the selected turn. If that fork fails — e.g. the composer shows:
■ Failed to branch before the selected prompt: the selected prompt was not found in the persisted thread
— then any user inputs that were queued while the fork was in flight get permanently stranded. They stay in "Queued follow-up inputs" forever and are never submitted, even after the composer returns to the Ready state. The queue just keeps growing with every new message and nothing is ever sent to the model.
Note: the "not found in the persisted thread" guard itself is legitimate defensive behavior (the visible transcript projection can't always be matched back to a persisted turn — e.g. after history pagination, or when large context blocks are injected as user messages by a wrapper). The bug is purely in the failure-handling path, which forgets to re-drive the input queue.
Root cause
Every successful fork path re-drives the follow-up input queue via maybe_send_next_queued_input():
- the sibling
AppEvent::ForkSession handler (codex-rs/tui/src/app/event_dispatch.rs),
- the startup path (
handle_startup_thread_started),
- the thread-start path.
But the branch-failure path does not. In codex-rs/tui/src/app_backtrack.rs:
pub(crate) fn restore_backtrack_prompt_after_branch_error(
&mut self,
prompt: UserMessage,
err: impl std::fmt::Display,
) {
self.chat_widget.restore_user_message_to_composer(prompt);
self.chat_widget.add_error_message(format!(
"Failed to branch before the selected prompt: {err}"
));
// <-- missing: maybe_send_next_queued_input(); the current thread is still live,
// but queued follow-ups are never re-driven, so they stay stuck forever.
}
Since the fork failed, the original thread stays live, but the queue is never flushed, so queued inputs are stranded.
What steps can reproduce the bug?
- In a live thread, enqueue one or more follow-up inputs (e.g. queue messages while a turn is running, or via a wrapper that injects inputs).
- Trigger prompt editing (Esc-Esc backtrack) and select a prompt whose fork will fail — the reliable way to force the failure is any state where the selected transcript prompt can't be resolved back to a persisted turn (
the selected prompt was not found in the persisted thread).
- Observe that after the error, the composer returns to
Ready, but the queued follow-up inputs remain in "Queued follow-up inputs" and are never submitted.
What is the expected behavior?
After a failed prompt-edit branch, since the current thread is still live, queued follow-up inputs should be submitted once the composer is idle — exactly like every successful fork path already does.
Additional information
I have a minimal fix and regression test ready (one-line fix + a test asserting the queued input is submitted after a failed prompt-edit branch, verified to fail without the fix and pass with it). openai/codex does not appear to accept PRs from external forks, so I'm filing this issue instead. Happy to share the patch/branch if useful:
pub(crate) fn restore_backtrack_prompt_after_branch_error(
&mut self,
prompt: UserMessage,
err: impl std::fmt::Display,
) {
self.chat_widget.restore_user_message_to_composer(prompt);
self.chat_widget.add_error_message(format!(
"Failed to branch before the selected prompt: {err}"
));
// The prompt edit never took effect, so the current thread stays live. Follow-up inputs
// queued while the fork was in flight would otherwise remain stuck, because unlike the
// successful fork paths this branch never re-drives the queue. Flush it here so queued
// messages are submitted once the composer is idle again.
self.chat_widget.maybe_send_next_queued_input();
}
What version of Codex CLI is running?
codex-cli 0.147.0
What platform is your computer?
Linux 5.15.120 x86_64 (also reproducible on other platforms — the bug is in the TUI prompt-edit/backtrack logic, not platform-specific)
What issue are you seeing?
When editing an earlier prompt (Esc-Esc backtrack → select a prompt → Enter), the TUI forks the thread before the selected turn. If that fork fails — e.g. the composer shows:
— then any user inputs that were queued while the fork was in flight get permanently stranded. They stay in "Queued follow-up inputs" forever and are never submitted, even after the composer returns to the
Readystate. The queue just keeps growing with every new message and nothing is ever sent to the model.Note: the "not found in the persisted thread" guard itself is legitimate defensive behavior (the visible transcript projection can't always be matched back to a persisted turn — e.g. after history pagination, or when large context blocks are injected as user messages by a wrapper). The bug is purely in the failure-handling path, which forgets to re-drive the input queue.
Root cause
Every successful fork path re-drives the follow-up input queue via
maybe_send_next_queued_input():AppEvent::ForkSessionhandler (codex-rs/tui/src/app/event_dispatch.rs),handle_startup_thread_started),But the branch-failure path does not. In
codex-rs/tui/src/app_backtrack.rs:Since the fork failed, the original thread stays live, but the queue is never flushed, so queued inputs are stranded.
What steps can reproduce the bug?
the selected prompt was not found in the persisted thread).Ready, but the queued follow-up inputs remain in "Queued follow-up inputs" and are never submitted.What is the expected behavior?
After a failed prompt-edit branch, since the current thread is still live, queued follow-up inputs should be submitted once the composer is idle — exactly like every successful fork path already does.
Additional information
I have a minimal fix and regression test ready (one-line fix + a test asserting the queued input is submitted after a failed prompt-edit branch, verified to fail without the fix and pass with it). openai/codex does not appear to accept PRs from external forks, so I'm filing this issue instead. Happy to share the patch/branch if useful: