codex queue: messages queued to exec threads are never delivered to a live turn, and can be silently destroyed
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of Codex CLI is running?
codex-cli 0.150.1 (standalone package install, macOS arm64)
What subscription do you have?
ChatGPT Pro
Which model were you using?
gpt-5.6-luna (reproduces regardless of model)
What platform is your computer?
macOS 15.7 (Apple Silicon)
What issue are you seeing?
codex queue --thread <uuid> --message <text> against a thread created by codex exec accepts the message (exit 0, "Queued message for thread ") but the message never reaches a live turn, and depending on a race it can be lost entirely.
From the rollout JSONL and ~/.codex/queue_1.sqlite (not model self-report): the queued item sits in queued_items while the exec turn runs. At the end of the turn, codex pops exactly one item and opens a new turn for it — then the exec process exits, and that turn is aborted 2-20 ms later (turn_aborted, reason interrupted). The model never runs on the message. Whether the popped message is persisted races the process exit: in 3 of 5 observed pops the user message landed in the rollout (so the next codex exec resume sees it as plain history, one invocation late); in 2 of 5 the rollout shows only turn_aborted and the message exists nowhere on disk afterwards (rollouts, sessions, archived_sessions, thread_history sqlite all grep-negative, with a surviving control token confirming the search works).
There is also no CLI way to list or flush a thread's queue, so a lost message leaves no trace, after a success message.
What steps can reproduce the bug?
- Terminal 1:
codex exec --skip-git-repo-check 'run: sleep 40; sleep 40; sleep 40, then reply listing any additional user messages you received, or NONE'and note the thread id from the startup output - Terminal 2, while it runs:
codex queue --thread <thread-id> --message 'MARKER-12345'(prints success) - Observe the exec run finish with "NONE"
grep -r MARKER-12345 ~/.codex/sessions— sometimes present as history (visible only to the next resume), sometimes absent everywherecodex exec resume <thread-id> 'list any user messages containing MARKER'— reports none on the first resume even when the text was persisted (that resume's turn-end pops/aborts it), and only a later resume sees it as history
What is the expected behavior?
Either the queued message is injected into the running exec turn (like queued messages in the TUI), or — if exec threads aren't meant to support queueing — codex queue should refuse to queue for them instead of accepting and then aborting/destroying the message. At minimum the pop should be transactional so an accepted message is never lost, and a codex queue list/flush surface would make the state inspectable.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the interaction between codex queue --thread and codex exec, then inspect ~/.codex/queue_1.sqlite alongside the rollout JSONL. Trace what happens when an exec turn ends and the queued item is popped. Done means the behavior is explicit for exec threads and an accepted message cannot disappear silently; add coverage for the observed race if the relevant tests are found.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, sqlite
- Domain
- backend, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100