[Bug] IDE extension redelivered a consumed user message hours later and executed stale file edits
What version of the IDE extension are you using?
- Codex IDE extension:
26.707.91948(openai.chatgpt, darwin-arm64) - Bundled/available Codex CLI:
codex-cli 0.144.5
What subscription do you have?
ChatGPT account sign-in (exact subscription tier not included here).
Which IDE are you using?
VS Code on macOS.
What platform is your computer?
macOS 14.7.2 (23H311), Apple Silicon.
What issue are you seeing?
A consumed user message was delivered again in the same Codex VS Code session more than three hours later with a new client_id. Codex treated it as a fresh instruction and modified two files, reverting newer committed work.
This was not only a stale assistant response in the UI: the rollout JSONL contains a second user-message delivery, followed by fresh tool calls that edited the worktree. This is a data-loss risk because an old destructive instruction can execute again without the user resubmitting it.
The original Japanese instruction was:
なんか違う。一旦queue.goは元に戻して。
("Something is wrong. Revert queue.go for now.")
It had already been handled during the original turn. Hours later, while the user was doing unrelated work, the same instruction was injected again and acted on.
What steps can reproduce the bug?
I do not yet have a minimal deterministic reproduction, but the recorded sequence is:
- Use a long-running Codex session in the VS Code extension.
- At
2026-07-17T08:55:11.585Z(17:55 JST), submit the instruction above. - Codex handles that instruction and the conversation continues through many later turns.
- At
2026-07-17T12:11:27.591Z(21:11 JST), the exact same user text appears again in the same rollout as newly delivered input. - The replayed input has a different
client_id:
- original:
cffd7415-e7d4-41f1-a116-7ea3d9f6ad4f - replay:
43c38110-8b11-46dd-a486-32db056c7682
- Codex then applies patches based on the stale instruction. The affected source file mtime becomes
21:12:32, and a related documentation file becomes21:13:01.
Session metadata:
- source:
codex_vscode - session/thread ID:
019f6d95-f448-77d0-a8e3-faab4e4cea1b - rollout:
~/.codex/sessions/2026/07/17/rollout-2026-07-17T09-59-31-019f6d95-f448-77d0-a8e3-faab4e4cea1b.jsonl - original message records: approximately lines 999-1000
- replayed message records: approximately lines 1312-1313
- subsequent file-edit records: approximately lines 1329-1345
Additional checks:
- Git reflog contained no reset, checkout, or restore corresponding to the change.
- The unexpectedly reverted source matched an older committed revision exactly.
- The current HEAD still contained the correct newer source.
- Restoring the two files from HEAD recovered the worktree and the relevant Go tests passed.
- The unrelated script the user manually ran does not write either affected file.
I can provide sanitized versions of the four relevant JSONL records if maintainers need the exact event envelopes. I cannot upload the complete rollout because it contains private source code and conversation content.
What is the expected behavior?
Once a user message has been consumed by a turn, it must never be delivered as fresh input again.
Resume, reconnect, replay, compaction, and extension/app-server recovery paths should preserve a stable message/turn identity and deduplicate already-consumed user input. A historical message must not receive a new client_id and trigger tool execution.
If recovery cannot determine whether an input was already consumed, the safe behavior is to stop and ask the user rather than execute an old file-modifying instruction.
Additional information
This appears related to replay/resume issues, but is distinct from:
- #17487, where a stale assistant final message reappears.
- #27894, where a manual steer becomes salient again during Goal mode.
Here the rollout contains a second delivery of the user message itself, with a new client_id, and it caused real filesystem mutations in a normal VS Code Codex session.
4 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I reviewed the two potential duplicates suggested by Codex Action.
In #33819, the stale input was actually delivered again in the VS Code extension with a different
client_id, then triggered new tool calls and filesystem modifications. I am therefore keeping this issue open as a distinct confirmed data-loss-impact case, while noting that #32688 may describe the underlying pending-message lifecycle problem. Maintainers can consolidate it if they determine the root cause is identical.The rollout JSONL is the load-bearing artifact here. A second delivery of an already-consumed user message, followed by fresh tool calls that edit the worktree, separates two failures that are easy to read as one.
The delivery path: a consumed message re-sent with a new client_id. If dedupe keys on client_id, a redelivery is indistinguishable from a new instruction by construction, so the turn executes again. Deduping on an identity derived from the message and its originating turn, persisted across reconnects, closes that specific path.
The apply path: this is why it did damage. The edit came from a view of the tree captured hours earlier and landed on a tree that had moved. Dedupe fixes this replay. It does not cover the class, because reconnect, crash recovery, queue redelivery, and retry-after-timeout can all resurrect a consumed instruction. The invariant that survives all of them sits at the write boundary: an edit derived from state read at time T must not apply if the target changed since T. Capture the file's version at read time (mtime plus size is usually enough, a content hash is stricter), carry it with the pending edit, and verify at apply time. A mismatch turns a silent revert into a rejected edit with a reason attached.
The failure is asymmetric, which is usually the argument for keeping the apply-time check even after the replay path is believed fixed. A rejected stale edit costs a retry. An applied stale edit destroys committed work silently, and the author finds out much later.
This is a very annoying issue. sending the same old messages again is potentially damaging. this needs to be fixed.