Repository navigation
Remote (Android) open times out on large threads while the host replies instantly #55005
Description
Environment
- Codex desktop
26.1013.4894.0(MSIX) on Windows 1110.0.26300 - Remote client: Android app (
app_server.client_name="codex_chatgpt_android_remote")
Symptom
Opening a long-running thread from the phone shows a load timeout and never renders. Short threads open normally, and the same threads load fine on the desktop client. Reported to feel worse after updating to 26.1013.4894.0, but I have no measurements from earlier builds, so I am not claiming a regression.
Measurements (same machine, same Wi-Fi, 7 threads, opened one by one from the Android client)
| Thread (first 8 of id) | Items | thread_items size |
Turns | Remote open |
|---|---|---|---|---|
01a13b71 |
981 | 137.8 MB | 47 | timeout |
01a0f4c0 |
3,754 | 157.4 MB | 181 | timeout |
01a0f10a |
3,786 | 5.9 MB | 191 | timeout |
01a0f93c |
81 | 0.1 MB | 4 | ok |
01a0f978 |
242 | 0.8 MB | 11 | ok |
01a0adb8 |
106 | 0.2 MB | 11 | ok |
01a0a36a |
138 | 0.3 MB | 35 | ok |
Every failure has ≥981 items; every success has ≤242 items.
Size is not the explanation: 01a0f10a is only 5.9 MB and still times out. It carries 3,786 items but almost no image data. So this is not bandwidth, not image payload, and not the network.
Host-side evidence (sanitized desktop logs, same second as each failed open)
- The host answers immediately and without error:
thread_lifecycle: composing running thread resume response thread_id=01a13b71-…lands in the same second as the request, witherrorCode=null. - No error code ever reaches the client — nothing like
-32003. The request simply never completes on the remote side. - The only client-side line is
Conversation state not found conversationId=…, which also appears for threads that open fine; it is noise, not the cause. - For the same threads, desktop-side
thread/read,thread/turnsandthread/items/*return in ~200 ms.
In short: the host prepares the whole history and replies at once; the remote client cannot get it across its timeout.
How to reproduce
- Create a thread with ~1,000+ items (a long asset/image session reaches this in a few hundred turns).
- Connect the Android remote client to the desktop host.
- Open that thread remotely → timeout. Open a small thread → fine.
- Open the same thread on the desktop → fine.
Expected
Remote open should behave like desktop: first screen renders quickly, older history streams in lazily. A thread should not have to transfer its entire item history before it becomes usable.
Suggestion
- Paginate hydration for remote clients: return the last N turns/items plus a cursor, and pull earlier ranges on scroll (
thread/itemsalready accepts ranges). - Cap what a single
thread/resumeresponse may contain, independently of thread size. - Secondary, size only:
imageGeneration.resultkeeps the full PNG as base64 insideitem_json. On this machine that is ~2 GB across 751 items, up to 971 MB in one thread. Keeping onlysavedPathwould shrink payloads by 10–50× — worth doing, but it will not fix01a0f10a, which is 5.9 MB.
All numbers above are row counts and byte sizes from the local thread database. No conversation content, file paths, account identifiers, or credentials are included.
Activity
github-actions commentedon Oct 18, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
kulear829 commentedon Oct 18, 2026
Related: #54751 — same remote pagination timeout, and one data point that changes the fix
#54751 (iPhone, same stack) already traces this to
thread/items/listreturning oversized pages becausethread_resume_redaction.rsstripsimageGenerationonthread/resumebut not in the paginated reads. That explains the image-heavy threads.My case adds a counterexample that a byte budget alone would not cover.
01a0f10atimes out with 5.9 MB total and 3,786 items — and no inline image payload at all. It has 345imageGenerationrecords, but every one of them has an emptyresult, and 93% of their combined 1.5 MB isrevisedPrompttext. Average item size is ~1.6 KB, so a 25-item page is roughly 40 KB.That thread should be cheap to fetch by any byte measure. It is simply fetched ~152 times in sequence, and the client gives up before first paint. Add a byte budget without a page budget and this thread still needs 152 round trips, so it still times out — it is the clean control case.
At the default 25 items per page, in my measurements the boundary looks like page count rather than bytes:
So the fix likely needs two parts:
Host side is not the bottleneck here:
thread/resumecomposes in <100 ms witherrorCode=null, and desktop-sidethread/read/thread/itemstake ~200 ms on the same threads. Everything up to the wire is fast; the remote client is the one that gives up.kulear829 commentedon Oct 18, 2026
Correction to my "page count rather than bytes" line — both dimensions can blow the budget
In my previous comment I wrote that the boundary "looks like page count rather than bytes". That is too strong, and #54751's own measurements show why: their control thread needs 33 pages but only 1.3 MB and opens fine, while their affected threads time out at 19 pages / 15.3 MB (largest page 10 MB) and 22 pages / 7.7 MB. Fewer pages, far more bytes, still fails.
Putting both datasets on the same two axes:
01a0f10a01a13b71Neither axis separates the groups on its own. 19 pages is low by count but fails on bytes; 152 pages is trivial by bytes but fails on count. What separates them is the combination — consistent with a single deadline that either dimension can exhaust, not with a page cap or a size cap alone.
So the two-part fix still stands, and it needs both halves:
01a0f10astill walks 152 pages of 40 KB each and still times out.Also worth noting for whoever reproduces this:
01a0f10atimed out twice tonight about 20 minutes apart. Both times the host loggedcomposing running thread resume responsea couple of seconds after the request with no error code, so this is deterministic rather than network flakiness.