Forked Codex sessions copy user messages from after the selected fork point

Open 💬 3 comments Opened May 4, 2026 by toptechie156
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Update

There's been no update on the app but I see the issue isn't happening anymore for me when I take a fork in the codex app.

Not sure exactly what changed. 🤔

What version of the Codex App are you using (From “About Codex” dialog)?

26.429.30905 (2345)

What subscription do you have?

Pro

What platform is your computer?

Darwin 25.4.0 arm64 arm

What issue are you seeing?

When creating a fork from an earlier point in a Codex session, the new fork includes user messages that were sent after the selected fork point.

Those copied messages also get rewritten with the new fork creation timestamp, which makes them look like they were sent fresh in the fork.

This makes it hard to trust the forked session history and makes debugging session timelines confusing.

Example

Parent session:

019df362-aa9f-7011-903e-4a0878d49fa0

Fresh fork:

019df3d2-6edb-7322-b537-34d4f10cb129

The fork session file:

~/.codex/sessions/2026/05/04/rollout-2026-05-04T21-59-07-019df3d2-6edb-7322-b537-34d4f10cb129.jsonl

The fork metadata says:

{
  "id": "019df3d2-6edb-7322-b537-34d4f10cb129",
  "forked_from_id": "019df362-aa9f-7011-903e-4a0878d49fa0",
  "timestamp": "2026-05-04T16:29:07.679Z"
}

But the fork contains these parent user messages, all rewritten to around 2026-05-04T16:29:08Z:

Now I want to have a completely branch new implementation...
Okay then based on this...
do not swap...
Use @Computer...
scroll and see everything

In the parent, those same messages originally happened earlier:

2026-05-04T14:29:36Z  Now I want to have...
2026-05-04T14:44:27Z  Okay then based on this...
2026-05-04T14:45:27Z  do not swap...
2026-05-04T14:57:37Z  Use @Computer...
2026-05-04T14:58:51Z  scroll and see everything

Expected Behavior

When I fork from an earlier point in a session:

  1. The fork should include only messages/events up to the selected fork point.
  2. Messages after the selected fork point should not be copied.
  3. Copied historical messages should preserve their original timestamps, or clearly be marked as copied history.
  4. Synthetic entries like <turn_aborted> should not appear as normal role=user messages.

Actual Behavior

The fork includes user messages from after the selected fork point.

The copied messages are written into the new fork with the fork creation timestamp, so they look like new messages in the fork.

The fork also includes synthetic entries like:

<turn_aborted>...</turn_aborted>

as role=user.

Impact

This breaks trust in session history. It becomes unclear which messages were actually sent in the fork and which were copied from the parent. It also makes timeline debugging and auditing user messages much harder.

What steps can reproduce the bug?

  1. In a codex session in mac app, take a fork from a previous message point in history.
  2. Compare the messages in context for both the original session and forked session.
  3. Ideally the forked session should have messages only till the point where it was forked in the original session but currently it copies all the messages (including one's from after the fork point)

What is the expected behavior?

_No response_

Additional information

_No response_

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 3 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #19975

Powered by Codex Action

toptechie156 · 3 months ago

There's been no update on the app but I see the issue isn't happening anymore for me when I take a fork in the codex app.

Not sure exactly what changed. 🤔

cesarbahena · 29 days ago

I can confirm this issue is still reproducible on a newer Windows build.

Environment

  • Codex Desktop: 26.721.11231.0
  • Platform: Windows
  • Bundled app-server runtime recorded in the rollout: 0.146.0-alpha.3.1
  • History mode: legacy

Observed behavior

I forked a conversation from an earlier message. The fork’s visible UI history ended at the selected point, but the child rollout contained later messages from the parent.

Those later messages:

  • Were copied into the child’s .jsonl rollout.
  • Were rewritten with the child fork’s creation timestamp.
  • Were available to the model even though they were not visible in the fork UI.
  • Caused the assistant to reference work that only happened later in the parent conversation.

This reproduced twice, approximately five minutes apart, with two separate child thread IDs.

Local evidence

Both child rollout files:

  • Have their own child session IDs.
  • Identify the same source using forked_from_id.
  • Contain parent turns created after the selected fork point.
  • Record the inherited turns at the child’s creation timestamp.

The Desktop log confirms successful thread/fork calls for both children.

I also inspected the packaged Desktop app.asar. The Desktop fork path sends a thread/fork request containing fields such as threadId, path, cwd, configuration, model, and developer instructions, but it does not appear to send lastTurnId.

This is significant because the documented app-server contract says that lastTurnId is what limits copied history to the selected turn:

https://github.com/openai/codex/blob/main/codex-rs/app-server/README.md

Without that boundary, the app-server copies history through the current tip of the source thread.

Impact

This is more than a confusing timestamp or UI-history problem. Later parent content becomes model-visible inside a fork that appears isolated at an earlier point.

That means “Fork from here” cannot currently be relied upon as a conversation isolation boundary. Prompting the model to ignore leaked history is not an adequate workaround because the unwanted content has already been supplied to the model.

Expected behavior

When Desktop forks from a selected message, it should:

  1. Pass the selected completed turn as lastTurnId, or use the corresponding supported boundary mechanism.
  2. Persist only history through that boundary in the child rollout.
  3. Ensure the UI-visible history and model-visible history are identical with respect to the fork boundary.

I can provide sanitized rollout metadata, timestamps, and Desktop log excerpts if maintainers need them. I am intentionally not posting transcript contents or complete local thread identifiers publicly.