openai / openai/codex

TUI: quick-cancelled optimistic prompt remains selectable but has no persisted UserMessage

Open
#38,210 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI session TUI
Dominant language
Rust
Stars
125k
Forks
19.5k
PR merge metrics
PR metrics pending

Description

What version of Codex CLI is running?

codex-cli 0.147.0

What subscription do you have?

ChatGPT subscription (exact tier omitted; this appears to be a local TUI persistence race)

Which model were you using?

gpt-5.6-sol

What platform is your computer?

Darwin 25.6.0 arm64 arm

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

Ghostty 1.3.1

Codex doctor report

Not included because it contains unrelated local paths. The relevant persisted state is summarized below.

What issue are you seeing?

If a newly submitted prompt is cancelled very quickly, it can remain visible in the TUI transcript and in prompt recall even though it never becomes a persisted UserMessage. Esc-Esc then offers that optimistic-only prompt as a backtrack target, but selecting it fails with:

Failed to branch before the selected prompt: the selected prompt was not found in the persisted thread

This is narrower than #37421 and does not appear to be covered by #37622. That fix reconstructs turns whose UserMessage already exists in buffered server notifications. In this reproduction, no user-message item exists in the rollout, replayable thread items, or thread database.

Observed state after the failure:

  • Cross-session prompt history contains the submitted text.
  • The TUI transcript contains a selectable user-history cell for it.
  • The rollout contains task_started followed by turn_aborted, with no user response_item for the submitted prompt.
  • The corresponding thread_turns row is interrupted, with an empty first_user_item_id.
  • There is no matching userMessage in thread_items.

The local timing was:

  • Prompt submission received.
  • Interrupt received approximately 743 ms later.
  • The task did not complete gracefully within the subsequent 100 ms cancellation window and was forcibly aborted.

The source appears to permit this split state:

Five UserPromptSubmit hooks were configured in the reproducing environment. The logs do not identify the exact pre-persistence stage active at cancellation, so this does not establish that any specific hook caused the failure; hook processing may simply widen the timing window.

What steps can reproduce the bug?
  1. Start a new interactive Codex CLI session.
  2. Submit a short prompt such as Hello.
  3. Immediately press Esc once, before the turn has durably recorded its user-message item.
  4. With the composer empty, press Esc twice.
  5. Select the just-cancelled prompt and press Enter.
  6. Observe that Codex restores the prompt but reports that it was not found in the persisted thread.

This is timing-sensitive interactively. A deterministic test could delay pre-persistence startup or a UserPromptSubmit hook, cancel before record_user_prompt_and_emit_turn_item, and then exercise Esc-Esc against the optimistic transcript cell.

What is the expected behavior?

The backtrack selector should never offer a prompt that cannot serve as a branch anchor. After quick cancellation, Codex should do one of the following:

  1. Persist the submitted user message before completing cancellation, allowing normal branching; or
  2. Mark/filter the optimistic-only transcript cell so Esc-Esc cannot select it; or
  3. Gracefully restore it for editing without attempting an impossible branch and without displaying an internal consistency error.
Additional information

#37622 fixes the related paginated-thread case where live turns exist in the replay buffer but not yet in the snapshot. Its added test supplies an ItemCompleted(UserMessage) notification. This reproduction has no such item to merge, so the new reconstruction path appears unable to resolve it.

No thread or session identifier is included because this is a public issue; sanitized additional diagnostics can be provided if needed.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with rust-v0.147.0/codex-rs/tui/src/chatwidget/input_submission.rs and app_backtrack.rs, then trace cancellation through record_user_prompt_and_emit_turn_item. Build a deterministic test that delays pre-persistence startup or a UserPromptSubmit hook, cancels before the user message is recorded, and exercises Esc-Esc. Done means the optimistic-only prompt cannot trigger an impossible branch or internal consistency error.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.