[Windows][Codex Desktop 26.721.4979.0] custom_tool_call_output is surfaced as a user message and re-enters the active turn
What version of the Codex App are you using (From “About Codex” dialog)?
Codex Desktop 26.721.4979.0
What subscription do you have?
ChatGPT Plus
What platform is your computer?
Windows (local workspace on D:)
What issue are you seeing?
Codex Desktop for Windows exposes internal custom_tool_call_output items as separate incoming user messages.
The leaked messages use the literal format:
~~~text
[tool output for call_<call_id>]
~~~
They contain raw tool results and the original call ID. Once this happens, each subsequent tool call can produce another apparent user message, creating a feedback loop.
The canonical local session JSONL records these items correctly as custom_tool_call_output; it does not persist them as role: "user". This points to Desktop/app-server event routing, renderer presentation, or the model-continuation bridge rather than the stored conversation transcript.
What steps can reproduce the bug?
- Open Codex Desktop on Windows.
- Create a new local task.
- Send a normal request that causes Codex to invoke a custom tool, such as exec.
- Wait for the tool to finish.
- Observe that the raw tool result appears as a new incoming message prefixed with [tool output for call_...].
- Continue the same turn and invoke another tool.
- The next tool result is again surfaced as an apparent user message.
Reproduced with:
- a failed tool call;
- a successful tool call;
- a large result;
- a result containing only {};
- multiple consecutive calls in one uninterrupted turn.
A manual interrupt is not required.
As an additional diagnostic, genuine human-authored messages carried a fixed marker; the leaked tool-result messages did not.
What is the expected behavior?
- A custom_tool_call_output item remains attached to its corresponding assistant tool call.
- It is never displayed or forwarded as a user-authored message.
- Tool output cannot steer or replace the active user turn.
- Its structured type and call association remain intact across app-server, Desktop renderer, and model-continuation boundaries.
Additional information
Impact
This is more than a cosmetic duplication issue:
- It breaks user/tool role attribution.
- Tool output may be interpreted as a new instruction.
- Raw logs, paths, environment data, or configuration output can be exposed in the conversation.
- Each diagnostic call can create another apparent user message.
- It becomes difficult to distinguish genuine user input from internal runtime data.
Session evidence (redacted)
Original affected task:
- Conversation ID: 019fadc3-f1d4-7ef0-afbe-48b135c2e2a0
- Example call ID: call_QHLP01byAeF6ROhRwX8On87C
- JSONL record type: payload.type = "custom_tool_call_output"
Fresh reproduction:
- Conversation ID: 019fadd3-0547-7241-9a27-6e6cabb239ee
- Turn ID: 019fadd3-9311-7cc1-8d61-9c9a6dab4a17
- Example call ID: call_0gpsFh108psz0FbEceelo02M
At one diagnostic snapshot, the new task contained:
- role: "user" items: 2
- custom_tool_call_output items: 14
- turn contexts: 1
The two user items were initial inputs. None of the fourteen tool outputs was persisted as role: "user", despite being surfaced live as incoming user messages. This indicates divergence between the canonical JSONL transcript and the live Desktop/context presentation.
Desktop log evidence
Immediately after the fresh conversation was created, Desktop logged events for a different, unknown conversation ID:
~~~text
2026-07-29T12:22:31.896Z Conversation created
conversationId=019fadd3-0547-7241-9a27-6e6cabb239ee
2026-07-29T12:22:31.988Z Received turn/started for unknown conversation
conversationId=019fadd3-92f8-7971-a08d-fcb2524e2316
rendererWindowAppearance=avatarOverlay
rendererWebContentsId=2
2026-07-29T12:22:32.210Z Received turn/started for unknown conversation
conversationId=019fadd3-92f8-7971-a08d-fcb2524e2316
rendererWindowAppearance=primary
rendererWebContentsId=1
2026-07-29T12:22:36.250Z Received turn/completed for unknown conversation
conversationId=019fadd3-92f8-7971-a08d-fcb2524e2316
~~~
The primary renderer and hidden avatarOverlay renderer received events from the same active task. This may indicate a race or incorrect mapping between provisional new-task IDs, final conversation IDs, and renderer subscriptions. I cannot confirm root cause, but it correlates with the reproduction.
Workarounds tested
- Creating a clean task did not prevent reproduction.
- Tool success/failure did not matter.
- Output size did not matter.
- The local JSONL was not manually edited.
- No OCR or workspace file was involved.
- Further tool use in the affected task was stopped to prevent additional leakage.
Requested fix
Please ensure that:
- custom_tool_call_output can never be converted into or rendered as a user-authored message.
- Tool-result items retain their structured type and call_id association through every layer.
- Unknown/provisional conversation events are not attached to another active task.
- Duplicate renderer subscriptions cannot forward the same event into the input channel.
- Desktop logs source and destination conversation IDs when remapping a newly created task.
- A safe “rebuild Desktop task state” or renderer-state recovery action is available without deleting session history.
Possibly related reports:
- #21167
- #25779
- #23725
I can provide redacted excerpts from the local session JSONL and Desktop log on request. I will not upload full JSONL files publicly because they contain conversation content and local paths.