app-server stream stalls after starting custom tool call with empty input
What version of Codex is running?
0.144.1
What platform is your computer?
Linux 6.17 arm64
What steps can reproduce the bug?
The failure is intermittent, observed through codex app-server --listen stdio:// using ChatGPT OAuth and gpt-5.6-sol with custom tools.
A typical affected turn:
- Start an app-server turn with a custom
exectool available. - Allow several reasoning/tool cycles to complete normally.
- After a completed reasoning item, the Responses stream starts the next custom tool call but stops before emitting its input.
The Codex structured log ends with:
Output item item=CustomToolCall {
id: Some("<redacted>"),
status: Some("in_progress"),
call_id: "<redacted>",
name: "exec",
namespace: None,
input: ""
}
No tool-input delta, output_item_done, app-server item/completed, or terminal turn/completed follows. No HTTP/SSE/auth/socket WARN or ERROR is logged. The connection remains open until the embedding client aborts it after its idle timeout.
The custom tool is never dispatched, so this is not a hanging command or missing tool result.
What is the expected behavior?
The stream should either:
- finish the custom-tool input and complete the item;
- emit a terminal Responses/app-server error; or
- detect/reconnect an idle partial stream without leaving the turn silently open.
What do you see instead?
Codex remains indefinitely between response.output_item.added for the custom tool call and its first/remaining input delta. The app-server never emits turn/completed, and the embedding client eventually reports a completion-idle timeout.
Observed locally:
- 11 completion-idle timeouts across multiple agents/workloads since July 10.
- Four deeply inspected failures show a partial custom-tool-call signature.
- Three failures ended exactly at
CustomToolCall(status=in_progress, input=""). - Successful turns occur between failures, so authentication, model access, and the app-server process are generally healthy.
Controlled follow-up:
- 0.143.0 cannot test GPT-5.6 because the backend returns
The 'gpt-5.6-sol' model requires a newer version of Codex(same for Terra/Luna). - 0.144.1 completed 8/8 controlled turns containing 10 separate custom exec calls each (80/80 tool calls), confirming the problem is intermittent.
Additional information
The embedding client is OpenClaw 2026.6.11 over stdio. Its timeout projection reported zero active items because the partial custom-tool start had not reached an app-server completed-item notification. Codex's own logs_2.sqlite is what exposed the in-progress item.
The first observed failures began after installing Codex 0.144.1, but this is correlation rather than a confirmed regression boundary because GPT-5.6 is rejected by 0.143.0.
A useful diagnostic improvement would be logging Responses stream lifecycle events/deltas and explicit close/error reasons around partial custom-tool items.
4 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Additional reproduction on Codex CLI 0.144.6 (the latest npm release at the time of testing) confirms the same failure and adds evidence that the Responses stream can resume only after an embedding client has already timed it out.
Environment
codex app-server --listen stdio://gpt-5.6-sol,xhighexectoolAll task, account, filesystem, thread, turn, call, and response identifiers are redacted.
Redacted timeline
response.in_progress, then completed two reasoning items.``
text
``Output item item=CustomToolCall {
id: Some("<redacted>"),
status: Some("in_progress"),
call_id: "<redacted>",
name: "exec",
namespace: None,
input: ""
}
item/started, tool-input progress, error, orturn/completed. Its last visible notification remained the precedingitem/completed, with zero active app-server requests and zero active turn items.turn/interrupt.``
text
``response.custom_tool_call_input.done
turn_aborted; no terminal assistant message or normalturn/completedwas produced before cleanup.This delayed
.doneevent is useful evidence: the transport/model stream had not reached a terminal failure when the five-minute client watchdog fired. It was an in-flight partial custom-tool call that remained invisible to the app-server client for almost six minutes.Context was not exhausted
The last token diagnostic reported:
The large context and
xhighreasoning may increase latency, but Codex did not classify this as a context-window or compaction failure.Current source-path observation
I also checked the 0.144 release branch and current
main:codex-rs/codex-api/src/sse/responses.rsconvertsresponse.output_item.addedandresponse.custom_tool_call_input.deltainto internalResponseEventvalues.codex-rs/core/src/session/turn.rshandlesOutputItemAdded(CustomToolCall)by installing an optional argument-diff consumer, but it does not emit an app-server-visibleItemStartedfor that partial custom-tool item.ToolCallInputDeltaonly emits a core event when the selected tool has a diff consumer that returns an event; ordinaryexecargument streaming therefore supplies no generic app-server liveness signal.response.output_item.done.That leaves app-server clients unable to distinguish a slow/stalled partial tool-call stream from a dead turn.
Suggested acceptance behavior
Any one of these would let embedding clients avoid premature mid-turn termination:
output_item.addedand input deltas;The important contract is that a partial custom-tool call must not remain indefinitely active inside Codex while being completely invisible to app-server clients.
Request for an invited contribution
Per the repository's contribution policy, I have not opened a pull request.
Would a Codex maintainer be willing to invite a focused PR for this issue? My proposed scope is:
response.output_item.addedstarts aCustomToolCall, before the full input oroutput_item.donearrives;output_item.done. I would update the app-server schema/docs if the approved approach adds protocol surface.If the team prefers an internal Responses stream-idle failure/retry boundary instead, I can implement that direction. Could a maintainer confirm whether this contribution is invited and which protocol shape is preferred?
Fresh 0.149.1 / current-main update
This failure still reproduces with Codex CLI 0.149.1 and a custom tool over
codex app-server --listen stdio://.In a redacted affected turn:
response.output_item.addedforCustomToolCall(status=in_progress, input="").output_item_done, tool dispatch, orturn/completedfollowed.The incomplete tool item was never persisted or executed.
Narrowed source seam
I rechecked current Codex
mainatd52478c:ResponseEvent::OutputItemAdded(CustomToolCall)assigns an item ID and may install an argument-diff consumer;OutputItemDone.The exact raw evidence window contained one core
OutputItemAddedrecord and zero app-server outgoing notifications. That rules out an embedding-client forwarding drop for this event and narrows the missing layer to Codex's core-to-app-server projection.Tested implementation shape (not merged or released)
I validated an isolated implementation with this contract:
rawResponseItem/startedwhenOutputItemAddedstarts aCustomToolCallorFunctionCall;OutputItemDone; andFocused validation passed:
The discriminating client test keeps the completion watchdog paused while the provider item is active, while a no-start control still times out normally.
This does not treat partial input as executable, replay side effects, or synthesize terminal completion.
As temporary containment, an embedding client can set its post-tool watchdog above 300 seconds so Codex's own stream-idle retry/error path runs first. That only removes the deadline collision; it does not fix the invisible active-item lifecycle.
Per the repository contribution policy, I have not opened a pull request. The implementation and test packet are ready if maintainers want this exact protocol shape or invite a contribution.