Bug report: Android Remote creates multiple tasks from one create_thread call
Summary
While controlling Codex on a Windows host from the ChatGPT Android Remote surface during a Realtime Voice session, a request to create one new projectless task produced seven separate top-level tasks.
This was not only a duplicated UI entry. The host persisted seven distinct threads with different thread IDs, turn IDs, rollout files, and projectless working directories.
Environment
- Host OS: Windows
- Codex desktop build:
26.721.11231.0
- Codex core/CLI version recorded in the rollout:
0.146.0-alpha.3.1
- Remote client reported by app-server:
codex_chatgpt_android_remote
- Remote client version reported by app-server:
dev
- Parent thread source: Realtime Voice
- New-task target: projectless
What happened
- From Android Remote, I asked an existing Realtime Voice thread to create one separate projectless task.
- The parent rollout contains only one
codex_app__create_thread tool call, with one call ID.
- That tool call returned one thread ID.
- However, the Windows host received seven
thread/resume requests for the same parent thread and the same active turn, all on the same app-server connection.
- The same connection then issued seven relevant
thread/start requests.
- Seven distinct top-level threads were persisted. They had the same delegated input and the same source parent, but different thread IDs, turn IDs, rollout files, and numbered projectless working directories.
Expected behavior
One codex_app__create_thread call should create exactly one new task. Resuming or reopening the active parent thread must not re-execute an already pending or completed side-effecting tool call.
Actual behavior
One recorded tool call resulted in seven real thread/start operations and seven persisted top-level tasks.
Sanitized host-log evidence
The values below are deliberately redacted. All seven resume requests referred to the same parent thread, active turn, client, and connection:
client_name="codex_chatgpt_android_remote"
client_version="dev"
connection_id=<SAME_CONNECTION>
thread/resume parent_thread=<PARENT_THREAD> active_turn=<ACTIVE_TURN> request_id=<R1>
thread/resume parent_thread=<PARENT_THREAD> active_turn=<ACTIVE_TURN> request_id=<R2>
thread/resume parent_thread=<PARENT_THREAD> active_turn=<ACTIVE_TURN> request_id=<R3>
thread/resume parent_thread=<PARENT_THREAD> active_turn=<ACTIVE_TURN> request_id=<R4>
thread/resume parent_thread=<PARENT_THREAD> active_turn=<ACTIVE_TURN> request_id=<R5>
thread/resume parent_thread=<PARENT_THREAD> active_turn=<ACTIVE_TURN> request_id=<R6>
thread/resume parent_thread=<PARENT_THREAD> active_turn=<ACTIVE_TURN> request_id=<R7>
The same remote connection issued seven new-thread requests during the incident window:
thread/start connection_id=<SAME_CONNECTION> client_name="codex_chatgpt_android_remote" request_id=<S1>
thread/start connection_id=<SAME_CONNECTION> client_name="codex_chatgpt_android_remote" request_id=<S2>
thread/start connection_id=<SAME_CONNECTION> client_name="codex_chatgpt_android_remote" request_id=<S3>
thread/start connection_id=<SAME_CONNECTION> client_name="codex_chatgpt_android_remote" request_id=<S4>
thread/start connection_id=<SAME_CONNECTION> client_name="codex_chatgpt_android_remote" request_id=<S5>
thread/start connection_id=<SAME_CONNECTION> client_name="codex_chatgpt_android_remote" request_id=<S6>
thread/start connection_id=<SAME_CONNECTION> client_name="codex_chatgpt_android_remote" request_id=<S7>
The parent rollout has only one creation call:
custom_tool_call name="exec" call_id=<ONE_CALL_ID>
input: tools.codex_app__create_thread({ prompt: <REDACTED>, target: { type: "projectless" } })
custom_tool_call_output call_id=<SAME_ONE_CALL_ID>
output: { "threadId": "<FIRST_CREATED_THREAD>" }
Suspected cause
The confirmed boundary is the Android Remote/app-server thread lifecycle, not model-level intentional delegation:
- The model-side parent rollout recorded one creation tool call.
- The Android Remote connection sent seven resumes and seven starts.
- Seven independent threads were actually persisted.
The likely failure mode is that repeated thread/resume handling at the Remote application/event layer replayed or redispatched the pending side-effecting create_thread action. This is not evidence of raw TCP packet retransmission. The create-thread tool does not expose an idempotency key, and the receiving path did not deduplicate the repeated execution using the original tool call ID.
The logs establish the repeated request sequence and persisted effects. They do not expose enough closed-client implementation detail to identify the exact Android callback or event-replay code path.
Suggested fix
- Treat the original tool call ID or a generated operation ID as an idempotency key for new-thread creation.
- Do not redispatch pending/completed side-effecting tool actions when an active thread is resumed.
- If the same create operation is received again, return the originally created thread ID instead of issuing another
thread/start.
- Add a regression test covering repeated
thread/resume while a create_thread tool call is in progress.
Privacy note
This report intentionally omits:
- account identifiers and email addresses;
- Windows username and home directory;
- project names and repository paths;
- complete thread, turn, message, call, and installation IDs;
- the original user prompt and transcript;
- raw rollout files,
logs_2.sqlite, and authentication/configuration files.
Sanitized excerpts can be provided privately if maintainers need request ordering or timestamps.
Bug report: Android Remote creates multiple tasks from one
create_threadcallSummary
While controlling Codex on a Windows host from the ChatGPT Android Remote surface during a Realtime Voice session, a request to create one new projectless task produced seven separate top-level tasks.
This was not only a duplicated UI entry. The host persisted seven distinct threads with different thread IDs, turn IDs, rollout files, and projectless working directories.
Environment
26.721.11231.00.146.0-alpha.3.1codex_chatgpt_android_remotedevWhat happened
codex_app__create_threadtool call, with one call ID.thread/resumerequests for the same parent thread and the same active turn, all on the same app-server connection.thread/startrequests.Expected behavior
One
codex_app__create_threadcall should create exactly one new task. Resuming or reopening the active parent thread must not re-execute an already pending or completed side-effecting tool call.Actual behavior
One recorded tool call resulted in seven real
thread/startoperations and seven persisted top-level tasks.Sanitized host-log evidence
The values below are deliberately redacted. All seven resume requests referred to the same parent thread, active turn, client, and connection:
The same remote connection issued seven new-thread requests during the incident window:
The parent rollout has only one creation call:
Suspected cause
The confirmed boundary is the Android Remote/app-server thread lifecycle, not model-level intentional delegation:
The likely failure mode is that repeated
thread/resumehandling at the Remote application/event layer replayed or redispatched the pending side-effectingcreate_threadaction. This is not evidence of raw TCP packet retransmission. The create-thread tool does not expose an idempotency key, and the receiving path did not deduplicate the repeated execution using the original tool call ID.The logs establish the repeated request sequence and persisted effects. They do not expose enough closed-client implementation detail to identify the exact Android callback or event-replay code path.
Suggested fix
thread/start.thread/resumewhile acreate_threadtool call is in progress.Privacy note
This report intentionally omits:
logs_2.sqlite, and authentication/configuration files.Sanitized excerpts can be provided privately if maintainers need request ordering or timestamps.