Skip to content

Codex Desktop writes empty assistant messages when continuing an older resumed thread #28751

Open

Description

@a09472610-star

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

Codex Desktop on Windows. Observed in logs: - Codex package: OpenAI.Codex_26.611.8604.0_x64__2p2nqsd0c76g0 - Browser/Codex release field seen in logs: 26.611.62324 - Session metadata CLI version: 0.136.0-alpha.2

What subscription do you have?

Plus

What platform is your computer?

Windows 10 / Windows Desktop.

What issue are you seeing?

When continuing an older Codex Desktop thread, Codex appears to complete the turn, but the assistant response is saved as an empty message.

The user-facing behavior is:

  • I send a message in an older thread.
  • The response may briefly appear or the turn appears to complete.
  • The final visible assistant message is empty / disappears.
  • The thread remains usable enough to open and resume, but future assistant responses in that thread are also saved empty.
  • Newer/fresh threads do not consistently show the same behavior.

The session file contains successful user messages followed by empty assistant messages:
{"timestamp":"2026-06-17T16:26:55.122Z","type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":""}]}}
{"timestamp":"2026-06-17T16:27:28.204Z","type":"event_msg","payload":{"type":"agent_message","message":"","phase":null,"memory_citation":null}}
{"timestamp":"2026-06-17T16:27:28.213Z","type":"response_item","payload":{"type":"message","role":"assistant","content":[]}}
{"timestamp":"2026-06-17T16:27:28.232Z","type":"event_msg","payload":{"type":"task_complete","turn_id":"019ed668-3880
The important part is:
agent_message message=""
assistant content=[]
task_complete last_agent_message=null

But the same turn has token usage recorded:
"last_token_usage":{"input_tokens":3326,"cached_input_tokens":0,"output_tokens":1572,"reasoning_output_tokens":0,"total_tokens":4898}

So this does not look like a normal "model returned no output" case. It looks like generated output was lost between the model/app-server pipeline and transcript persistence/rendering.

What steps can reproduce the bug?

I do not have a minimal deterministic reproduction yet, but the observed path is:
Open an older Codex Desktop thread created several days earlier.
Let Codex resume the thread.
Send a new user message.
Codex starts and completes the turn.
The session file records an empty assistant message with content: [].
The UI shows no usable assistant response / the response disappears.
Relevant logs around resume show that the old thread loads successfully:

2026-06-17T16:04:46.504Z info [AppServerConnection] response_routed ... conversationId=019ea5d4-bd16-7332-9cdf-ad2e9b0663dc ... errorCode=null ... method=thread/read
2026-06-17T16:04:52.820Z info [AppServerConnection] response_routed ... conversationId=019ea5d4-bd16-7332-9cdf-ad2e9b0663dc ... errorCode=null ... method=thread/resume
2026-06-17T16:04:52.865Z info [electron-message-handler] maybe_resume_success conversationId=019ea5d4-bd16-7332-9cdf-ad2e9b0663dc latestTurnStatus=completed markedStreaming=true turnCount=9

A later turn starts successfully:
2026-06-17T16:26:54.975Z info [AppServerConnection] response_routed ... conversationId=019ea5d4-bd16-7332-9cdf-ad2e9b0663dc ... errorCode=null ... method=turn/start

Then the persisted transcript contains an empty assistant message and task_complete with last_agent_message=null.
In one earlier retry on the same old thread, a rollback happened before another empty response was recorded:
2026-06-17T16:04:56.425Z info [AppServerConnection] response_routed ... conversationId=019ea5d4-bd16-7332-9cdf-ad2e9b0663dc ... method=thread/rollback

What is the expected behavior?

When a resumed old thread completes a turn, the assistant response should be persisted and rendered normally.
If the response cannot be generated or persisted, Codex should show a visible error instead of writing: {"role":"assistant","content":[]}
and marking the task complete with:
"last_agent_message": null

Codex marks the turn complete, records token usage, but persists an empty assistant message:
agent_message message=""
assistant content=[]
task_complete last_agent_message=null
This makes the thread appear broken: the user sees no answer, and subsequent attempts in the same old thread can repeat the same empty-output behavior.

Additional information

Additional diagnostics
I checked for the previously reported rollout is empty / thread/read failure pattern, but this does not appear to be the same bug.
For this affected thread:
thread/read returns errorCode=null
thread/resume returns errorCode=null
turn/start returns errorCode=null
no rollout is empty error was observed for this thread
the failure is visible in the session JSONL as empty persisted assistant content
There were unrelated warnings/errors in the same Codex Desktop logs, including Git dubious ownership and Windows workspace dependency warnings, but the old thread itself resumes successfully before the empty assistant message is written.
Impact:
This is data-loss-like behavior for long-running Codex Desktop threads. Older threads can become effectively unusable because new assistant responses are completed but stored as empty messages, making it impossible to continue work from that thread.

Activity

  1. added
    bugSomething isn't working
    windows-osIssues related to Codex on Windows systems
    app-serverIssues involving app server protocol or interfaces
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    on Jun 17, 2026
  2. a09472610-star commented on Jun 17, 2026

    @a09472610-star
    Author

    Workaround: creating a branch/fork from the affected thread makes the conversation usable again. Continuing the original resumed thread writes empty assistant messages, but the branched thread works normally.

  3. zmc1997 commented on Sep 2, 2026

    @zmc1997

    I am also seeing the completed-but-empty-response symptom on macOS with a newer build:

    • ChatGPT desktop: 26.820.71523 (build 7226)
    • Bundled Codex CLI/app-server: 0.150.0-alpha.8
    • macOS 14.4.1, arm64
    • Model visible in the affected task: GPT-5.6 Sol, High reasoning

    In the latest occurrence:

    1. I sent a normal code-review follow-up in an existing local workspace conversation.
    2. The turn ran for 3m40s.
    3. The UI then showed the turn as finished: duration and feedback controls were visible, and the composer returned to the normal Send state.
    4. The assistant response area was completely empty. There was no visible error and no usable answer.
    5. Retrying or asking the same conversation to continue is not a reliable recovery path.

    From the UI alone I cannot yet determine whether the generated response was persisted and dropped by the live projection, or whether the turn completed with empty assistant content. Either case should produce a visible synchronization/error state rather than silently presenting a successful empty turn.

    This may be part of the same broader turn-lifecycle/recovery problem reported in #24287. I added the related stuck-stream behavior there: #24287 (comment)

    Expected behavior:

    • A completed turn must expose a non-empty assistant response when generation succeeded.
    • If output generation, persistence, or projection fails, Desktop should display an explicit recoverable error.
    • Desktop should rebuild the response from canonical history when live projection loses it.
    • Retrying should continue the unfinished logical task without silently returning another empty turn.

    No thread IDs, raw logs, screenshots, local paths, repository names, account details, or project content are included.

  4. StevenVincentOne commented on Sep 6, 2026

    @StevenVincentOne

    Same signature on 26.901.51231 (Windows 11 + WSL2 Ubuntu 24.04, Windows-native agent): turns run to completion (~80–88s of billed work) but persist nothing — null assistant payload on the completion record and an empty items array on authoritative re-read.

    Four occurrences, two models (gpt-5.6-sol ×3, gpt-6-astra ×1), so this looks host-side and model-independent. Consistent with the continuation trigger in this issue: one failing turn was a same-directory fork, another a same-task follow-up. One notable isolation: an occurrence reproduced with no worktree provisioning involved at all, so this is not a provisioning artifact.

    Impact beyond the lost text: the failure hides behind a success status, and reruns are expensive at frontier-reasoning cost. Current mitigation is persisting responses to files, which should not be load-bearing.

    Question for triage: does the empty-write-on-continuation hypothesis cover same-task follow-ups and forks, or should those split into their own issue? Turn IDs available on request (truncated here): 01a07884-…, plus three further occurrences on 2026-09-06.

  5. StevenVincentOne commented on Sep 7, 2026

    @StevenVincentOne

    Follow-up with app-server log evidence from one of our occurrences (same build, 26.901.51231), which strengthens the continuation hypothesis.

    The empty turn's ID appears in 86 log rows, including 5 identical ERRORs spanning the turn's full ~87s lifespan, all in run_turn.prepare_sampling_request_input: Custom tool call output is missing for call id: call_…. So every sampling-request assembly failed validation because a prior tool call's output was absent from thread state; the turn burned its duration retrying and terminated complete with nothing — matching the billed-time-with-no-payload signature.

    Context: this turn was a same-directory fork (resumed state), cross-checking the continuation trigger. None of the error rows contain any WSL/UNC/path content, and environment resolution logged only a benign warning. Caveat: the missing output could itself be the victim of an earlier failed write rather than the original sin — but the fatal blow lands in state assembly, not the filesystem handoff.

    Full turn/thread/call IDs available on request if they help correlate.

  6. rc314159-creator commented on Sep 7, 2026

    @rc314159-creator

    Additional sanitized reproduction on macOS, Codex surface in ChatGPT desktop 26.901.51231, model gpt-6-astra.

    This has the completed-but-empty signature, but it is an existing-thread scheduled heartbeat that DID execute its read-only tool successfully. It is not the "automation prompt was never dispatched" case.

    Observed sequence on 2026-09-07 (UTC):

    • 10:48:22.819: task_started
    • 10:48:36.271: command item completed with exit_code=0 and non-empty output
    • 10:48:40.382: completed AgentMessage, phase=final_answer, content=[{"type":"Text","text":""}]
    • 10:48:40.384: persisted assistant message, phase=final_answer, content=[{"type":"output_text","text":""}]
    • 10:48:40.469: task_complete, last_agent_message=null, duration_ms=17650, time_to_first_token_ms=4386

    The UI showed a completed duration row and feedback controls, with an empty assistant response area. This is not merely a populated response hidden by the renderer: the stored response is empty too. We do not have the raw provider stream, so we cannot distinguish model-produced emptiness from output transformation before persistence. The final sampling usage record reports output_tokens=4; this alone does not establish the cause.

    Important distinction for the fix:
    The automation legitimately requested quiet behavior when nothing required intervention. The turn's heartbeat response contract nevertheless required a non-empty structured result, including a quiet-status message for DONT_NOTIFY. The actual final contained neither that structured result nor ordinary text. Quiet success and an invalid empty result should be distinguishable.

    Public source examined at 0df3975:

    • codex-rs/core/src/stream_events_utils.rs, finalize_non_tool_response_item: whitespace-only combined text becomes last_agent_message=None.
    • codex-rs/core/src/session/turn.rs: the no-follow-up path can return Ok(last_agent_message), including None.

    These observations describe a possible permissive completion path, NOT proof that this public revision exactly matches the installed Desktop implementation or that all None completions are bugs.

    Suggested acceptance criteria:

    1. Valid quiet heartbeat results remain quiet and have an inspectable execution status; no business-prompt change or forced NOTIFY is required.
    2. A heartbeat missing its required terminal result must not be rendered as an unexplained successful blank answer. Surface an explicit output/protocol failure, or perform bounded recovery that preserves already-completed tool work.
    3. Do not blindly replay successful tools to recover missing final text.
    4. Regression tests cover non-empty NOTIFY, non-empty DONT_NOTIFY, empty/whitespace final after successful tool output, and an actual stream failure.
    5. Do not treat an earlier commentary message as proof that the required final response was delivered.

    Related: #25619 and its community null-tail recovery patch address adjacent failure paths. We have not established a stream failure or missing-tool-output validation error in this occurrence, so those should not be assumed to be this reproduction's root cause.

    No screenshot, raw rollout, private prompt, thread/turn IDs, hostnames, filesystem paths, project data, or credentials are attached.

  7. RongNianXin commented on Oct 6, 2026

    @RongNianXin

    We also observed a related empty-output completion on Windows Codex Desktop.

    In one captured turn:

    • the delegated input was present as a `function_call_output`;
    • the Responses request returned HTTP 200;
    • token usage was recorded;
    • the persisted assistant final text was empty;
    • no reply tool call was emitted;
    • task completion recorded `last_agent_message=null`;
    • logs did not indicate context-window or token-limit exhaustion.

    The user-visible result was a completed turn with no usable response. Expected behavior is a visible failed/diagnostic state rather than successful completion with empty content.

    The evidence is redacted and contains no task IDs, paths, credentials, or private project data. We cannot distinguish model-produced emptiness from proxy conversion or client persistence without the original provider stream and app-server trace.

  8. Jason-Wang313 commented on Oct 6, 2026

    @Jason-Wang313

    Additional Windows reproduction on 2026-10-06, explicitly reported by the user in Codex Desktop:

    • Codex Desktop: 26.924.22138, build 11645, production channel.
    • Surface: an existing ordinary ChatGPT conversation shown in the Codex Desktop sidebar, not a local coding task.
    • The user sent a substantive follow-up in an older conversation. An assistant answer appeared to stream and was almost finished, but then disappeared completely at finalization.
    • Retrying in the same conversation did not recover it. The substantive prompt was accepted twice, followed by two short answer retries.
    • A supported read of the conversation afterwards reports all four user turns as completed with error: null, but each turn contains only the user message and no assistant item.
    • The conversation is now idle; no generation remains active.
    • The readable history does not expose context_length_exceeded or any other explicit failure.

    This extends the completed-but-empty symptom to the ChatGPT-conversation surface in the Windows desktop app. It is consistent with streamed output failing to persist or synchronize at finalization, although the available evidence cannot distinguish provider output loss, final-item persistence failure, or projection/rendering failure.

    Expected behavior:

    1. A response visible during streaming should be finalized and recoverable from canonical history.
    2. If finalization or persistence fails, the turn should show an explicit recoverable error rather than completed/error: null with no assistant item.
    3. Retrying should not silently create additional completed user-only turns.

    No conversation content, IDs, screenshots, account details, local paths, or credentials are included.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesbugSomething isn't workingsessionIssues involving session (thread) management, resuming, forking, naming, archivingwindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions