Repository navigation
Responses WebSocket falls back when compacted replacement_history contains large inline images #24550
Description
What version of Codex CLI is running?
codex-cli 0.133.0.
The original affected session metadata includes codex-cli 0.130.0, but the WebSocket fallback was reproduced from a copied session using the current Codex CLI/App around 0.133.0.
What subscription do you have?
ChatGPT Pro 20x.
Which model were you using?
gpt-5.5 with reasoning_effort=xhigh.
What platform is your computer?
macOS arm64.
What terminal emulator and version are you using (if applicable)?
iTerm2 3.6.10.
The affected thread was resumed through Codex CLI/App flows. The reproduction used copied CODEX_HOME directories and codex resume against the same session JSONL payload. No terminal multiplexer was intentionally used for the reproduction session; separate monitoring/caffeinate processes may have been run in other terminals.
Codex doctor report
Redacted summary from codex doctor --json:
- overallStatus:
ok - codexVersion:
0.133.0 - install method:
brew - runtime platform:
macos-aarch64 - installation:
installation looks consistent - config:
config loaded - model:
gpt-5.5 - model provider:
openai - auth:
auth is configured - auth mode:
chatgpt - provider reachability:
active provider endpoints are reachable over HTTP - WebSocket reachability:
Responses WebSocket handshake succeeded - WebSocket handshake result:
HTTP 101 Switching Protocols - WebSocket wire API:
responses - terminal:
iTerm2 - terminal version:
3.6.10 - terminal size:
211x98 - state paths:
state paths and databases are inspectable - active rollout files:
110 files, 1371653678 total bytes, 12469578 average bytes
I am not pasting the raw doctor JSON because it contains local usernames, paths, project names, and state locations.
What issue are you seeing?
A long-running Codex thread consistently falls back from Responses WebSocket to HTTPS when resumed.
This may share a root cause with #24388, because both involve large input_image payloads retained inside compacted replacement_history. The observed failure mode here is different: instead of remote compaction failing with context_length_exceeded, the Responses WebSocket stream closes before response.completed, retries several times, and then falls back to HTTP.
I was able to reproduce the fallback using a copied CODEX_HOME, and then eliminate the fallback by removing only inline image payloads from compacted replacement_history.
Observed WebSocket failure pattern:
stream disconnected - retrying sampling request (1/5 ...)
stream disconnected - retrying sampling request (2/5 ...)
stream disconnected - retrying sampling request (3/5 ...)
stream disconnected - retrying sampling request (4/5 ...)
stream disconnected - retrying sampling request (5/5 ...)
falling back to HTTP
The HTTP fallback then proceeds, but the affected thread becomes prone to long idle periods.
What steps can reproduce the bug?
I cannot attach the raw session JSONL because it contains local paths, prompts, tool output, and image payloads. The structural reproduction I used was:
- Start from a long-running Codex thread with multiple compactions and historical image inputs.
- Confirm that compacted
replacement_historycontains retainedinput_imagepayloads. - Copy the affected session JSONL into a clean temporary
CODEX_HOME. - Resume the same thread from the copied session.
- Observe that WebSocket warmup succeeds, but the actual resumed turn payload fails over WebSocket, retries 5 times, and falls back to HTTP.
- Create another copy of the same session JSONL.
- Replace only
input_imageitems insidetype: "compacted"records with small text placeholders. - Resume the same thread from that sanitized copy.
- Observe that
responses_websocketcompletes normally, with no HTTP fallback and nostream disconnectedretries.
Control reproduction with copied session JSONL:
- WebSocket warmup succeeded.
- The actual resumed turn payload failed over WebSocket.
stream disconnectedoccurred 5 times.- Codex fell back to HTTP.
This suggests the issue is reproducible from the session/history payload itself, not from the original live ~/.codex state.
Compaction-only sanitized reproduction:
- I replaced only
input_imageitems insidetype: "compacted"records with text placeholders. - Non-compacted history was left mostly unchanged.
Before sanitization:
- Session JSONL size: ~703 MB
- Largest compacted JSONL line: ~17.4 MB
- Total
input_imageentries: 1789 input_imageentries inside compacted records: 1277input_imageentries outside compacted records: 512- Latest compacted
replacement_history: ~17.39 MB - Inline image data in that replacement history: ~17.17 MB
- Image data share of replacement history: ~98.75%
After compaction-only sanitization:
- Session JSONL size: ~195 MB
- Largest compacted JSONL line: ~241 KB
input_imageentries inside compacted records: 0input_imageentries outside compacted records: 509
Result:
responses_websocketcompleted normally.responses_http: 0stream disconnected: 0- fallback: 0
- turn completed successfully.
This suggests the failure is specifically tied to inline images retained in compacted replacement_history, not simply to any historical input_image item anywhere in the session JSONL.
I also tested a full-image-sanitized copy, where all input_image items were replaced with text placeholders. That also completed normally over WebSocket.
What is the expected behavior?
Either:
- compacted
replacement_historyshould not retain large raw inline image payloads unnecessarily, - the Responses WebSocket transport should handle this payload shape reliably,
- Codex should surface a more specific close reason, such as payload size / unsupported multimodal replay / request shape issue, or
- Codex should automatically recover from this history shape without requiring manual session JSONL surgery.
A session should not repeatedly fail Responses WebSocket and silently fall back to HTTP because compacted history retained large inline image payloads.
Additional information
The thread did not always fail WebSocket. It worked over WebSocket for several days before the first hard fallback.
The first hard fallback appeared after a compaction where replacement_history had grown to ~17.38 MB and contained 42 inline images.
In the latest compaction:
- Messages in replacement history: 382
- Messages containing images: 18
input_imagecount in replacement history: 42- Image bytes inside image-containing messages: ~99.88% of those messages
The images appear to be retained as historical user message content inside compacted replacement history.
Privacy note: I am not attaching raw rollout/session files because they contain private prompts, tool output, local paths, and inline image data. I can provide further redacted structural data if useful.
Activity
github-actions commentedon May 26, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
SylvainWinning commentedon May 26, 2026
This lines up with what I see in the repo as a plausible failure boundary:
CompactedItemwithreplacement_history: Some(new_history.clone())replacement_historyas the live replacement historyA useful narrow test case might be: construct a compacted rollout item whose
replacement_historycontains one or moreinput_imagecontent items with large data URLs, resume/reconstruct it, and assert either that compacted history no longer carries raw image payloads into the next sampling request or that it is converted into a bounded placeholder before the WebSocket request is built.The key distinction in the report seems important: images outside compacted records did not trigger the fallback after sanitizing only compacted
replacement_history, so I would keep the first fix/test scoped to compacted history rather than all historical multimodal content.VVittgenstein commentedon Jun 1, 2026
Adding a related Windows Desktop datapoint. Same underlying data shape as this issue (
compacted.payload.replacement_historyretaining inline images), but the observed symptom on my machine was Desktop session/rollout bloat and UI hangs rather than only Responses WebSocket fallback.Environment:
OpenAI.Codex_26.527.3686.0_x64__2p2nqsd0c76g0Sanitized structural stats from the affected rollout:
Largest relevant record:
Why I think this belongs here:
response_itemandevent_msgforms.payload.replacement_history, creating another large durable record.%USERPROFILE%\.codex\sessionsrestored Desktop responsiveness.I also added the broader Windows Desktop hang/session-list datapoint in #24676, but this comment is specifically for the compacted
replacement_historyamplification aspect.Privacy note: I am not uploading the raw rollout, screenshots, sqlite databases, or unsanitized logs because they contain private conversation/image data.
FiredPhoenixIR commentedon Jul 16, 2026
Windows confirmation: retained compacted images caused WebSocket fallback
I reproduced this on:
codex-cli 0.144.4gpt-5.6-solreasoning_effort=maxThe affected long-running session repeatedly produced:
It then fell back to HTTPS and remained on HTTPS after stopping and resuming the session. Other Codex sessions on the same machine continued working normally over WebSockets, suggesting this was specific to the affected session payload rather than general network or WebSocket availability.
Structural measurements from the affected rollout before repair:
input_image/data-URL occurrencesreplacement_history: 82 items and 13 inline imagesI closed the session, created a byte-identical backup, and performed a schema-aware cleanup:
input_imageobjects with smallinput_textplaceholdersencrypted_contentand all other fields untouchedAfter cleanup:
input_imageobjectsThis provides a Windows confirmation that the retained compacted image payload was causal. It appears to be the same retention mechanism described in #33493 and #23257.
Uploaded affected thread: 019f6455-ea0e-7481-ba54-5c665a6ea33f
Uploaded investigation and recovery thread: 019f6964-aa8c-7901-9dbb-90dd8249fb05
Note: Both threads were uploaded through Codex feedback.
The affected thread contains the original WebSocket failure and HTTPS fallback. The investigation thread contains the structural rollout analysis, schema-aware image cleanup, validation results, and confirmation that the same affected session resumed successfully over WebSockets afterward.
i69699 commentedon Aug 3, 2026
I traced the generic disconnect message to the established Responses WebSocket close-frame path on current
main(79479cd).The pump correctly forwards
Message::Close(frame), butrun_websocket_response_streamcurrently matchesMessage::Close(_)and discards both the close code and reason before returning:websocket closed by server before response.completedThat means a server close such as
1009 / Message Too Bigis indistinguishable from an ordinary transport disconnect in the CLI. This explains why an oversized image-heavyreplacement_historycan produce five generic reconnect attempts without surfacing the actionable server reason.I prepared a minimal diagnostic-only patch that:
code=1009 reason=Message Too BigPatch commit: i69699@b1a2aaf
Validation on Windows:
cargo +stable nextest run --no-fail-fast -p codex-api: 159/159 passedcargo +stable clippy --fix --tests --allow-dirty -p codex-api: passed with no warningsThe branch is ready if a maintainer would like to invite a PR.
lanchuanshuang commentedon Aug 13, 2026
macOS reproduction on the current Desktop build
I added a detailed macOS corroboration to #36232. The retained inline-image/history shape also matches the root cause tracked here.
Environment
26.803.616010.147.0-alpha.6.526.5, Apple Silicon (arm64)openaiprovidergpt-5.6-sol, xhigh effortTwo independent affected tasks
In both tasks, a new turn records the user message but no subsequent model event before:
stream disconnected before completion: error sending request for url (https://chatgpt.com/backend-api/codex/responses)Other tasks in the same Desktop process, on the same network and built-in provider, remained healthy. Task A's last successful model input was only 78,018 / 258,400 tokens, so serialized history byte size appears to be a pressure signal independent of the displayed token usage.
The visible failure in these two cases reaches the HTTPS Responses endpoint rather than only surfacing a WebSocket fallback, but the causal payload signature is consistent: compaction leaves large inline image/tool payloads in the active history, and retrying the affected task resends them.
i69699 commentedon Aug 14, 2026
I ran a separate local-only structural scanner against the pre-sanitization copy rather than installing another recovery tool. It does not access the network, SQLite databases, or the Codex app; it never emits source paths, session IDs, prompts, tool arguments, image contents, or source hashes. The source file's size and modification time were unchanged before and after scanning.
Public-safe result:
replacement_history: 49replacement_history: 405 messages, 39 messages with images, 44input_image/data-URL entries, 16,591,360 Base64 payload bytes (estimated decoded image bytes: 12,443,474)replacement_history: 16,763,158 bytes, 410 messages, 39 messages with images, the same 44 image entries and 16,591,360 Base64 payload bytesThis independently confirms that the active compaction payload is dominated by retained inline image bytes. The attachments are the local read-only scanner and its public-safe JSON result.
codex-issue-24550-public-evidence.zip
i69699 commentedon Aug 15, 2026
I implemented a candidate fix for the retained inline-image payload issue:
The change externalizes inline Base64 images returned in compacted replacement history into a content-addressed, per-thread store. Compacted history retains only bounded
codex-image://references, andview_imageresolves a referenced image on demand with size, path, and SHA-256 validation. Remote image URLs remain unchanged.Targeted compaction, storage, integrity, path-safety, follow-up request, and
view_imagetests pass, as doesjust fix -p codex-core.I attempted to open a PR, but the compare page currently says that pull requests are limited to repository collaborators, and the API returns
Resource not accessible by integration. Could a maintainer review/cherry-pick this commit, open a PR from the branch, or advise on obtaining collaborator access? I am happy to adjust the implementation based on review feedback.i69699 commentedon Aug 21, 2026
Thanks — this control makes the boundary between the two issues much clearer.
We already have separate candidate transport fixes alongside the compaction/image change:
The important remaining gap is that the first fix only applies when the peer provides a standard 1009 close frame. Windows socket errors 10053/10054 do not necessarily expose that close frame, so they can still enter the generic retry budget. PR #38681 also preserves fallback only for delegated sessions; your data suggests that later turns, Desktop reconstruction, or another Responses client recreation path may still lose the fallback state.
I therefore think these should remain two independently reviewable fixes:
Your historical control is especially useful because it shows that payload size is the trigger, while the repeated retry/fallback scope is the latency regression.
HyperHe-dev commentedon Aug 29, 2026
Downstream amplification after HTTP fallback
I think #24550 is part of a larger performance failure loop. The original report demonstrates much of the first half; I was able to reproduce and quantify the slowdown after HTTP fallback:
This does not prove that payload size alone caused the initial WS disconnect. It describes the amplification that occurs once the incremental path is lost.
In
rust-v0.150.0-alpha.12.2,view_imageconverts the file to a Data URL and returns it as anInputImage. The generic function-output truncation logic budgets text but copiesInputImagepayloads without accounting for their serialized bytes. Therefore, network history size can grow with every image even when token/context accounting does not reflect that growth proportionally.The WS path can send only incremental items when the request extends the previous one and
previous_response_idremains available. Otherwise it sends the full active input. The HTTP fallback path rebuilds and submits the full prompt; I could not find an equivalent incremental path there.This means fallback can turn one large upload into approximately:
where
Skis the accumulated active-history size at each model/tool loop.Compaction reset and reproduced the slowdown
One affected task remained in HTTP fallback throughout the following experiment:
view_imageuse resumed: 25 inline images / approximately 84.8 MiB of Data URLs, followed by intervals of 5m28s, 5m25s, and 6m09s.Across 53 measured intervals, the median was 3m00s and the maximum was 9m18s, while the tool executions themselves had a median runtime below one second.
The transport state did not change: reducing the accumulated history temporarily restored normal latency, and rebuilding the image history reproduced the slowdown.
These images were added by ordinary
view_imagecalls after compaction; they were not images retained inside the compaction'sreplacement_history.Macro impact
A separate affected task ran for approximately 8h05m and contained:
Approximately 26,983 seconds / 7.50 hours, or 92.8% of the entire task, were spent between tool completion and the next model-produced response item.
This is end-to-end latency rather than pure upload time, but it shows where the dominant cost accumulated.
The two behaviors that seem worth addressing independently are:
view_imageoutputs;Fixing either would reduce the severity; fixing both would break the failure loop.
i69699 commentedon Aug 31, 2026
Thanks for the downstream-amplification analysis. I hardened the candidate implementation against the additional failure modes discussed here and pushed the updated single commit:
What this candidate now covers:
codex-image://references and reloads exact bytes throughview_imageonly on demand;This intentionally does not claim to solve the other half of the loop: new ordinary
view_imageoutputs can still accumulate after a compaction until the next compaction, and WebSocket retry / durable HTTP-fallback state is unchanged. Those remain independent transport/live-history fixes.Validation completed:
cargo clippy -p codex-core --lib --tests -- -D warningsI attempted to open the PR directly, but GitHub returned
i69699 does not have the correct permissions to execute CreatePullRequest. If the direction is acceptable, could a maintainer invite collaboration, open a PR from the comparison, or cherry-pick the commit?dreampiggy commentedon Oct 9, 2026
Additional macOS CLI reproduction on 2026-10-09, with recovery after removing historical images from the same resumed thread. This closely matches this issue and #33493; HTTP-only transport did not by itself restore responsiveness in this observation.
Environment
codex-cli 0.156.1, macOS 26.6.2, Apple Silicon, ChatGPT authentication.gpt-6-astra, reasoning effortmedium.--no-daemon. This has not been retested on the latest CLI release.Observed sequence
Resuming the existing thread through the built-in OpenAI provider repeatedly established the Responses WebSocket connection successfully, then failed sending the request:
The CLI retried through
Reconnecting ... /5. Successful handshakes distinguish this observation from a simple failure to establish a WebSocket connection.Explicitly resumed with an HTTP-only provider:
Logs confirmed
transport="responses_http". At 12:03:18 UTC+8 the sampling request started; when checked around 12:06:48 there was still no assistant response or recorded request error. The user then exited the CLI. This was an interrupted wait, not a measured terminal HTTP timeout.With the thread stopped, backed up the rollout and replaced historical
input_imagecontent with small text markers, including images insidecompacted.payload.replacement_historyandguardian_history. Local image references and embedded screenshot data in UI/tool metadata were also removed. Text, tool records, thread ID, ordering and timestamps were preserved.Resumed the same thread with the same HTTP-only configuration and no intentional network/hosts changes. The sampling request started at 12:08:28; an assistant message was recorded at 12:08:35, and the turn finished at 12:08:36. The user confirmed the session worked again.
Structural measurements
input_imageoccurrences in originalresponse_itemrecordsinput_imageoccurrences across the complete persisted rollout, including repeated compaction snapshotsreplacement_historyAfter cleanup: 31,284,707 bytes, a reduction of 57,799,771 bytes. Codex's
thread/readsuccessfully parsed all 134 turns. The first successful post-cleanup turn reported 178,578 input tokens.These are persisted-rollout sizes, not measured serialized request or wire sizes. The 90 occurrences include historical snapshot duplication; I am not claiming all 90 images or the whole 89 MB file were sent in one request. The active replacement history retained 20 images, with one subsequent image.
Interpretation and recovery request
The before/after result strongly implicates retained image history as a contributor to the unusable thread. It does not establish a precise byte limit, a WebSocket 1009 close code, which network component failed, or how much of the HTTP wait was upload versus backend processing. This was a natural before/after comparison across process restarts, not a controlled repeated benchmark; WebSocket behavior after cleanup was not retested.
IPv6 was considered because of #27381, but the affected process's observed TCP connections were IPv4. DNS routed the endpoint through private IPv4 addresses in this environment, so an intermediary remains a possible contributing factor. No hosts pinning or IPv6 setting change was needed for the observed recovery.
A supported remove historical images while preserving text/tool history recovery command would be valuable, alongside bounded retained-image bytes and actionable transport diagnostics. Manual JSONL editing is not a clean public workaround: although inference recovered, the local history projection subsequently warned
thread-store internal error: durable rollout shrank before projection. An official operation should keep the durable rollout and derived history index consistent.Only aggregate diagnostics and sanitized error text are included here; no private conversation, screenshots, session identifiers, account credentials or project paths are attached.
anvsk commentedon Oct 14, 2026
Windows reproduction: retained screenshot payloads, repeated 10053 disconnects, and successful recovery after removing images from the latest compacted snapshot
Adding new diagnostic evidence to #24550 rather than opening a duplicate. Related: #33493 and #40323.
Environment
26.1007.71326.--version:codex-cli 0.162.0-alpha.17.2.Microsoft Windows NT 10.0.26200.0.gpt-6-astraandgpt-6.1-sol; the successful recovery test usedgpt-6.1-sol.User-visible failure and reproduction sequence
One long-running local conversation became unresponsive while other conversations remained usable. The affected conversation had accumulated screenshots used for temporary visual checks; most were no longer needed.
继续(continue).thread/compact/start. The request is accepted, but remote compaction also fails with 10053 and retries.This is an observed existing-thread reproduction, not a clean synthetic minimal reproduction. The private original transcript and screenshots are not attached publicly.
Measured before/after comparison
The latest compacted snapshot was created at
2026-10-14T07:52:39.367Z. Itspayload.replacement_historycontained 29 complete inlineinput_imagedata URLs. One additional image was present in subsequent history.恢复测试成功(“Recovery test successful”)The snapshot size decreased by approximately 98.47%. Sizes were measured consistently using Python
len(json.dumps(replacement_history).encode()), with default serialization. They are local history serialization measurements, not captured HTTP/WebSocket payload sizes. We did not capture wire traffic and cannot claim that exactly 16 MB was uploaded on every request.The complete rollout before the image repair was 607,846,787 bytes. This is persistent transcript size, not the request size.
The last recorded successful model usage before the incident was 169,660 input tokens with a reported 258,400-token context window. The final recovery test reported 149,698 input tokens, 149,376 cached input tokens, and 7 output tokens. These are different turns, not a controlled token-cost experiment; cached input tokens must not be interpreted as billed quota loss.
Redacted log evidence
Trace prefixes, turn IDs, local paths, project content, and credentials are omitted. The error message means “An established connection was aborted by the software in your host machine.”
Recovery evidence from the same conversation's persisted events:
Exact local recovery and limitations
After backing up and hash-verifying the rollout, the failed isolated compaction process was stopped and the conversation was archived to release its writer. Only the latest compacted record's 29 inline images were replaced with text references to preserved local image files. The rest of the transcript lines were verified byte-for-byte unchanged at the time of repair. Original transcript image entries, text, and the newer image were retained. The conversation was then restored and the diagnostic message retried.
This was a manual workaround, not a supported product fix or a recommendation to edit live rollout files. Archive/unarchive without the image replacement had already failed. The final diagnostic succeeded after the replacement. This is strong evidence of a history-shape/retained-image sensitivity, but not proof of a particular transport size limit or which component caused 10053. Only a short recovery test was validated; long-term stability was not established.
Requested product changes
Account impact and compensation request
The affected user reports that this incident wasted one Codex usage-reset card and an additional nearly 50% of their usage allowance. They request two complimentary usage-reset cards (two usage resets) as compensation.
This consumption impact is the user's report; the attached technical evidence does not independently attribute or quantify account-level quota charges. Please investigate the account usage and consider granting the two requested resets. If compensation must be handled by OpenAI Support rather than GitHub maintainers, please route or advise the appropriate private support path. Private transcripts and authentication credentials are intentionally excluded from this public report.
Affected OpenAI / ChatGPT account email:
anvskyi@gmail.com. This is the email recorded in the affected user's current local Codex ChatGPT login. The account owner explicitly requested including it here so OpenAI can identify the account for investigation and, if approved, credit the two requested usage resets to this account. Please perform any additional account verification privately through OpenAI Support.pamelagrainsn-cmyk commentedon Oct 16, 2026
Additional Windows reproduction: image-heavy saved thread fails WebSocket sends (10054), falls back to large HTTP requests; synthetic probe receives close 1009 above 16 MiB
The affected user reviewed and explicitly authorized publication of this redacted diagnostic report.
Summary
An existing image-heavy Codex desktop thread repeatedly reconnects and falls back from WebSocket to HTTP. Subsequent productive requests repeatedly prepare approximately 63 MB compressed HTTP bodies containing historical image data.
Restarting the desktop app did not resolve the problem. A separately authorized, “reply only OK, do not use tools” diagnostic turn in the affected thread took approximately 76 seconds and also fell back to HTTP.
Separate synthetic tests, containing no conversation history or screenshots and using
generate:false, observed a size boundary: a message of 16 MiB minus one byte completed, while 16 MiB plus one byte received a peer WebSocket Close 1009.Please investigate aggregate request-byte handling and provide a supported recovery path that preserves the original thread and all records.
Environment
The embedded runtime version above is not a claim about OpenAI’s server-side version.
1. Actual affected-thread behavior
On October 17, 2026, approximately 01:38–01:39 UTC+08:00, one diagnostic turn requested only “OK,” with no tools or continuation of the original task.
Observed sequence:
The turn eventually returned “OK” after 75,797 ms.
The original task was not continued.
2. Evidence of repeated historical-image payloads
For the preceding ten consecutive model requests in the affected thread:
responses_http.A local structural reconstruction of active history found 44 historical inline image entries, totaling 83,663,628 data-URL bytes in each reconstructed request history. No new image entries were added during the inspected turn.
These are historical image entries repeatedly carried forward—not 44 newly captured screenshots per request.
Measurement limitation: image composition was reconstructed locally, not obtained from captured HTTP bodies. Prepared-body metrics are not exact wire traffic or VPN billing measurements; interrupted requests may not have transmitted their entire bodies.
3. Separate low-traffic synthetic size control
These tests did not use the affected thread, conversation text, screenshots, or model generation.
Conditions:
generate:falsepermessage-deflatenegotiatedresponse.completedresponse.completedresponse.completedThe measured outbound WebSocket frames totaled approximately 34 KB, excluding TLS/TCP and handshake overhead.
4. Interpretation and limits
The evidence strongly suggests that aggregate inline-image bytes can exceed an operational WebSocket message-size boundary, preventing successful initialization and subsequent incremental continuation.
However:
5. Existing image-reference work does not establish legacy recovery
Relevant official changes include:
The inspected history-replay implementation in the installed runtime, stable 0.163.0, and preview 0.164.0-alpha.1 continues to use
InlineAttachmentStorewithout uploading or migrating recorded images.Therefore, support for file references does not by itself recover an existing inline-image-heavy thread.
This evidence is being added to #24550 rather than opening a duplicate issue.
Requested resolution
Please:
Privacy
This report contains no conversation bodies, screenshots, Base64 image data, local paths, thread identifiers, account identifiers, authentication tokens, cookies, or authorization headers.
Please request narrowly scoped, redacted diagnostics if additional evidence is necessary, rather than requiring a full conversation upload.
pamelagrainsn-cmyk commentedon Oct 16, 2026
请求明确修复版本,或提供保留原线程和全部截图的官方恢复流程
我们希望继续使用官方Codex客户端,不替换运行时、不安装请求改写代理,也不通过迁移线程或删除截图绕过问题。
截至2026年10月17日,我们核实的环境为:
26.1013.31256,build20586,生产渠道;更新检查返回up_to_date。0.163.0-alpha.10.2。gpt-6.1-sol。已有证据
请官方明确回答
一、是否已有修复版本?
请提供具体桌面版本、内置运行时版本及对应修复链接,并说明修复是否:
如果尚未发布,请说明问题是否已确认、由哪个问题单跟踪,以及是否有预计发布窗口。
二、如果尚无修复版本,请提供官方恢复流程。
我们要求恢复流程能够:
请明确:官方
/compact是否适用于这种已经超限的线程;如果压缩本身也失败,应使用什么受支持的恢复机制。请不要仅建议反复重试、重启、换网络或新建线程。我们愿意提供必要的脱敏版本、时间、请求大小及错误信息,但本次不会上传聊天记录、截图、认证信息或完整日志。如需补充,请明确最小诊断字段及官方私密提交渠道。
这是对正常长线程及截图工作流造成实际影响的可靠性问题。我们需要明确的官方修复或恢复路径,而不是自行改造客户端。
pamelagrainsn-cmyk commentedon Oct 16, 2026
补充:官方
/compact成功,但活跃上下文仍保留约71 MB内嵌旧图片在此前反馈的同一原线程中,我们通过桌面客户端原生
/compact命令尝试恢复,没有修改配置、安装补丁或迁移线程。环境仍为:
26.1013.31256,build205860.163.0-alpha.10.2gpt-6.1-sol本次结果
2026年10月17日,UTC+8:
completed,没有任务错误,随后线程空闲。注意:以上是执行压缩所发送的请求大小,不是压缩后下一轮请求的大小。
压缩后仍存在的大图片上下文
只读检查新生成的压缩检查点:
压缩后保留的图片均位于用户消息中,仍为完整内嵌Data URL,并未转换成小型引用。图片字节仅减少约15%。
这里的71.14 MB是内嵌Data URL的序列化字节数,不是解码后的图片文件大小,也不是压缩后实际网络上传量。完整替换历史的紧凑JSON序列化大小为 71,334,919字节。
压缩后客户端记录的上下文用量约为 88,058 tokens。这说明,Token上下文明显下降,并不意味着序列化请求已足够小。
尚未验证的部分
我们没有发送任何后续测试消息,也没有继续原任务。因此:
但目前保留的内嵌图片字节,仍明显超过此前合成对照中观察到的约16 MiB消息边界,连接重建时仍存在完整上下文过大的风险。
请官方明确说明
/compact成功后仍保留约71 MB用户图片,是否属于预期行为?本次仅提供脱敏统计;不上传私人聊天、图片、认证信息或完整日志。
pamelagrainsn-cmyk commentedon Oct 16, 2026
Follow-up: successful
/compactstill followed by repeated ~53 MB HTTP request bodiesA read-only inspection of existing local logs found that successful manual compaction did not eliminate large HTTP requests in the affected conversation.
Environment
26.1013.3656.00.163.0-alpha.10.2Observed evidence
/compactcompleted successfully on October 17, 2026, at 03:13:43 UTC+8.responses_http.falling back to HTTP. We found no evidence establishing successful incremental WebSocket continuation after compaction.Measurement limitations
These are logged serialized/compressed request-body sizes, not packet captures or VPN billing totals. The ten records represent approximately 532 MB of prepared compressed request bodies. We did not inspect request payload contents, so we cannot prove that every request contained exactly the same 30 images, although the retained-history and request-body sizes are consistent with that explanation. The initial connection-failure cause remains unconfirmed.
No dedicated reproduction requests were initiated during the inspection; however, the diagnostic conversation itself involved model calls and should not be treated as a zero-traffic operation.
Requested official resolution
Please provide either:
Please clarify whether retained-image byte budgeting and recovery from sticky HTTP fallback are tracked separately, and identify the owning issue or fix PR.
Starting a new conversation, deleting screenshots, manually editing session files, or installing a custom runtime does not satisfy the requested recovery requirements.
Only sanitized versions, counts, byte sizes, timestamps, and generic transport markers are included here. No conversation records, screenshots, raw logs, request bodies, credentials, cookies, or authentication headers are attached.
pamelagrainsn-cmyk commentedon Oct 16, 2026
Follow-up: multiple threads repeatedly submit large HTTP bodies during successful model/tool progression—not failure retries
We performed a read-only correlation of the latest 10 logged HTTP request-body compression records from each of four existing local conversations.
Environment
26.1013.3656.00.163.0-alpha.10.2Results
“Successful progression” means successful model/tool execution steps, not an assessment that every business action was useful.
Why these are not simply repeated failed requests
We did not classify requests as successful based on HTTP 200 alone. We correlated:
For conversation B, the final request started at 00:47:18. The conversation recorded
turn_abortedwith reasoninterruptedat 00:47:36. This was an interrupted new step, not a failure retry.Earlier WebSocket failures exist in the broader investigation. The conclusion here is narrower: no failure retries were identified among these 40 sampled HTTP request-body records.
Retained media remains relevant after compaction
These observations distinguish old-image retention after compaction from new tool-image accumulation.
Impact and measurement limits
The sampled records total approximately 796 MB of prepared zstd-compressed request bodies, despite predominantly successful progression.
These are request-layer measurements—not packet captures, confirmed WAN delivery totals, VPN billing totals, or proof that every outgoing body contained exactly the same images.
The practical concern is that ordinary successful model/tool loops can repeatedly incur large full-context submissions, even without an active failure-retry loop. Reducing retries alone would not resolve this behavior.
Requested official resolution
Please provide:
Migration, screenshot deletion, manual JSONL/database editing, or a custom runtime does not satisfy the requested recovery requirements.
No private conversation content, screenshots, raw logs, request bodies, credentials, cookies, authentication headers, local paths, or thread identifiers are attached.
pamelagrainsn-cmyk commentedon Oct 17, 2026
Follow-up: file-ID support exists, but historical inline images are not converted during replay — request for a supported, non-destructive recovery path
Related: #45971. This follows up on the retained-image / WebSocket fallback evidence already reported in this issue.
We have continued a read-only review of the official source to distinguish support for image file references from recovery of existing image-heavy threads.
Official source findings
PR #45794 added support for image
file_idreferences in inputs and tool outputs.PR #46065 routed prepared images through
AttachmentStorebefore recording history. Its description explicitly states that history replay remains onInlineAttachmentStore, does not upload recorded images, and preserves existing file references.Consequently, replaying an existing thread does not automatically upload its historical inline images to attachment storage and replace them with file IDs. “Not uploading during replay” here refers to attachment-store uploads; it does not establish that those inline bytes are omitted from subsequent full model requests.
We compared the relevant public source paths in:
0.163.0-alpha.10.20.163.00.164.0-alpha.3As checked on October 18, 2026, these versions retain the historical replay path using
InlineAttachmentStore. For example: replay code in 0.164.0-alpha.3.PR #54398 stores generated-image results as attachment references. Its scope does not establish that it converts existing user screenshots or eliminates historical input-image retransmission.
These are runtime/source observations, not a claim that a particular desktop update has already shipped an end-to-end recovery feature.
Additional local, read-only observations
For one successful compaction at 2026-10-18 06:54:51 UTC+08:00:
The structural measurements and request-body sizes are not packet-capture measurements or VPN billing totals. They do not independently identify the disconnecting endpoint or prove a particular WebSocket size limit.
Requested official clarification and recovery path
Please provide a supported operation to convert historical inline images in an existing thread's working context into valid, durable attachment references while preserving:
Can such a conversion prevent the old image bodies from being resent in full after resume, compaction, or reconnect? Please clarify reference permissions, lifetime, and recovery if a reference expires or becomes unavailable.
If a fix already exists, please identify:
If this is not yet supported, please confirm the limitation and provide an official temporary recovery method. Creating a new thread, deleting screenshots, manually editing history, or installing a third-party runtime does not meet this recovery request.
Privacy: This comment contains only redacted structural measurements and public source links. No conversation transcript, screenshot, raw log, local thread identifier, credential, cookie, or authentication header is attached or uploaded.
pamelagrainsn-cmyk commentedon Oct 17, 2026
Follow-up: new Desktop screenshots also remain inline — please distinguish enabling file-ID storage for new images from recovering historical images
This supplements the previous follow-up. Related: #45971.
The affected user explicitly authorized this redacted follow-up. No conversation transcript, screenshot, raw log, credential, or local thread identifier is attached.
Scope and environment
Read-only checks on October 18, 2026:
26.1013.4894.0.0.163.0-alpha.10.2.Evidence: the local app-server defaults to an inline image store
In the official source corresponding to the installed runtime:
The app-server passes
codex_core::passthrough_image_store()when constructing the thread manager:message_processor.rs.
passthrough_image_store()constructsInlineAttachmentStore:thread_manager.rs.
Despite the method name
upload(), this implementation simply returnsOk(UploadResult::Inline { bytes: request.data }); it does not perform a remote attachment upload or produce a file ID:attachment-store/src/lib.rs.
Image preparation distinguishes three outcomes: successful inline bytes, a successful file reference, and an upload error that falls back to inline:
image_preparation.rs.
This distinction matters: an image can remain inline because that is the successful default storage result, not necessarily because a remote upload failed.
Local observations agree with the default-inline path
In the affected thread's existing persisted model-history records:
failed to upload prepared imagewarning in the retained native logs or the current Desktop-session logs.The absence of a warning is not proof that every upload attempt succeeded: native per-thread logs have bounded retention, and the logs do not expose a per-image storage-result trace. The stronger evidence is the default source path together with the persisted input representation. We are not claiming to have instrumented the live storage object or captured an attachment upload.
No documented end-user switch was found
We checked the official configuration reference and the installed runtime's configuration schema. We did not find a supported setting that selects a remote image attachment store or enables automatic file-ID conversion for new screenshots.
PR #45556 establishes the upload/resolve integration interface, but does not itself document a Desktop end-user activation procedure. Likewise, general Files API / image
file_idsupport does not establish a supported bridge into an existing Desktop local thread using ChatGPT authentication.Please correct this finding if a documented switch or supported activation flow exists.
Requested official answer: two separate deliverables
A. Prevent new image accumulation
Please specify whether the shipping Windows Desktop local-thread path can upload each new screenshot once and record a durable
file_idinstead of inline Base64.If supported, provide:
If not supported, please confirm the limitation and identify the fixing PR, release/version, or supported temporary alternative. A developer integration hook alone is not an end-user recovery procedure.
B. Recover existing inline-image history
Separately, please provide a supported, non-destructive procedure to convert the working context's historical inline images while retaining the original thread identity, all messages and screenshots, screenshot viewability, project associations, and task continuity.
Enabling file-ID storage only for future screenshots would not remove the historical inline-image burden already documented in this issue. Please do not treat these as the same fix.
We want to remain on the official Desktop client without manual history edits, deleted screenshots, third-party runtimes, or request-rewriting proxies.
Privacy: Only redacted structural measurements and public source links are submitted. No private conversation, images, raw logs, credentials, or authentication headers are uploaded.
pamelagrainsn-cmyk commentedon Oct 18, 2026
Follow-up: Latest source still retains sticky HTTP fallback and inline-image history replay — request for a confirmed fix or supported recovery procedure
Following our previous reports, we reviewed the latest public stable release,
rust-v0.163.0, and the current main-branch snapshot:8c076942cb70fba8e5c4732c23f1faabc4aed484The desktop updater also reported
up_to_datefor our production channel. We understand this only confirms update eligibility, not that the reported issue has been fixed.Source findings
1. HTTP fallback remains sticky across turns.
The stable release and inspected main snapshot contain the same test:
websocket_fallback_is_sticky_across_turnsIt explicitly verifies that, after WebSocket failures trigger HTTP fallback, the next turn remains on HTTP without another WebSocket attempt.
Stable-release test
Inspected main-branch test
2. Replayed inline images are not automatically migrated to file references.
The inspected history-replay implementation explicitly avoids uploading or migrating recorded history and uses
InlineAttachmentStore. Existing file references are preserved, but legacy inline images remain inline.History-replay implementation
3. Compaction does not impose a serialized-image byte budget.
The inspected compaction implementation retains messages and images using a token budget. This does not guarantee that the resulting working context is small enough in serialized bytes to avoid large reconnect requests.
Compaction implementation
Why this matters
We understand that a new connection using
store=falsemay need to replay the required working context after the documented 60-minute connection limit. We are not asking to reuse an expired connection-local cache.The concern is the combination of:
Previously reported request-layer logs showed repeated large HTTP request bodies after fallback. These are not measurements of individual WebSocket frames, and we are not claiming that a particular WebSocket size limit has been conclusively established.
Requested response
Please provide either:
Please clarify separately:
No chat archives, screenshots, complete request bodies, credentials, cookies, or authentication headers are attached to this follow-up.
pamelagrainsn-cmyk commentedon Oct 18, 2026
Follow-up: token-bounded compaction still retains multi-megabyte user images; requesting a supported, history-preserving fix
Please investigate and provide an actionable resolution for this issue. It has repeatedly disrupted the affected user's work and amplified traffic and waiting time. We need a confirmed fix version, or an official recovery procedure that preserves the original thread, all visible history, and all original-resolution images.
Refined failure chain and evidence boundaries
Connection lifetime and reconstruction. The Responses WebSocket connection lifetime is approximately 60 minutes. A replacement connection cannot simply reuse the old connection-local continuation cache. Connection expiry, compaction/history changes, and other lost incremental preconditions can require a full working-context request. This is not limited to automatic compaction.
Large complete messages, not just large compact requests. Earlier bounded synthetic testing observed a 16 MiB message-size boundary and remote close code 1009. This is an observed boundary for the tested route, not a claimed officially documented universal limit. A full reconstruction can encounter the same risk whether caused by expiry, compaction, or another reset. Existing production logs include five-attempt retry sequences; compact and ordinary-generation retry budgets must not be conflated. The later generic “websocket closed by server before response.completed” failures do not themselves establish close code 1009 or prove a size-related cause.
Successful compaction is not a serialized-byte safeguard. In the inspected successful compaction on October 18, twelve tool-image occurrences left the active working window while three user images remained. This is a result of this particular compaction, not a claim that every compaction removes every tool image. Retention uses model-oriented token estimates, which do not guarantee a bounded serialized request body.
Repeated HTTP uploads are an implementation/path behavior, not an HTTP requirement. On the inspected Codex client/subscription path, ordinary HTTP model requests do not use server-side context continuation; each request submits the required working context again. Retained inline image bytes are therefore resubmitted, including in normal tool-result-to-model continuations, not only failed retries. A local tool execution alone is not being counted as a model upload.
In short: retained images enlarge the working context → loss of incremental preconditions requires full reconstruction → large complete messages increase the risk of WS failure → HTTP fallback repeatedly carries the required working context and inline images. This explains the measured large-payload samples; it does not establish that all disconnects or slow responses have this cause.
Latest privacy-safe measurements
The latest successful compaction committed at 2026-10-18 13:51:49 UTC+8:
These are application-recorded request-body sizes, not packet-capture measurements or VPN billing totals. We did not generate new model requests to collect this follow-up. Earlier evidence in this issue separately documents approximately 53 MB compressed HTTP requests; those older samples should not be conflated with this smaller post-compaction window.
Relevant upstream work checked
As of this check, the latest public stable release is rust-v0.163.0, and main is 8c07694.
Requested resolution
Please provide:
This comment contains only sanitized structural measurements and public source links. No chat transcript, screenshots, image payloads, credentials, cookies, or authentication headers are attached.
pamelagrainsn-cmyk commentedon Oct 18, 2026
Additional provenance evidence: TLS verification enabled, Google Trust Services issuer recorded, and peer-initiated 1009 at the observed 16 MiB boundary
Following the previous clarification, a read-only review recovered the original October 17 test output, which contains stronger TLS and close-frame provenance than the separate October 18 Rust diagnostic. Please use the following to clarify the enforcing layer and provide a supported recovery path.
No network test was rerun for this review. No private transcript, image, raw log, credential, or authentication header is attached.
Original test: October 17, 2026, UTC+08:00
Target:
wss://chatgpt.com/backend-api/codex/responses.The preserved test code and structured output establish:
ssl.create_default_context()and passed that context to the WSS connection.tls_check_hostname=trueandtls_verify_mode=2(ssl.CERT_REQUIRED).max_size=None.proxy=Noneto the Python WebSocket client. This disables that client's explicit proxy selection; it does not prove the traffic bypassed VPN/TUN routing.response.completedresponse.completedThe over-limit exception recorded
rcvd_then_sent=true, received code 1009, and sent code 1009. Thus this was a received peer Close followed by the client's reply, not merely a locally generated receive-size exception. The tiny request after the rejection also completed.The two boundary payloads used the same synthetic JSON content, differing only by two trailing JSON whitespace bytes. No private screenshots or conversation were used. Exactly 16,777,216 bytes was not tested.
What this establishes, and what remains missing
The evidence strongly points away from ordinary router/VPN TCP forwarding performance as the direct explanation of this particular size-dependent, valid WSS Close 1009. A non-terminating TCP forwarder does not normally have access to the decompressed WS message or the ability to originate an authenticated application Close frame inside the destination TLS session.
However, we are not claiming complete forensic exclusion of every intermediary:
Maintainer clarification and resolution requested
Please provide a concrete answer to these questions:
Related implementation and lifecycle evidence is already recorded above in this issue. This supplement adds only sanitized TLS settings, issuer information, timing, sizes, and close-order observations; it does not upload the underlying conversation, screenshots, raw logs, or credentials.
AmuroRX-93 commentedon Oct 18, 2026
Please add an optional “Load historical attachments on demand” setting.
In long-running chats, Codex repeatedly includes historical inline images in HTTP requests. On my Mac, compressed request bodies were around 10–17 MB, even on turns without new images.
With this setting enabled, please preserve the original attachments and transcript, keep summaries and references in the active context, and reload old attachments only when needed.
Please make this work with existing chats. Repeatedly starting new chats disrupts ongoing tasks.
Environment: macOS desktop app, bundled Codex CLI 0.162.0-alpha.17.2.
niel-malan-sa commentedon Oct 18, 2026
Please provide a supported desktop fix that stops repeated uploads of historical images while preserving existing chats, their visible history, and the visual context needed to continue working.
Additional redacted observations from macOS:
up_to_datefor this installation.Could maintainers identify a fixed desktop build, a supported setting, or an official recovery procedure that:
If stored image references are the intended solution, please clarify how desktop users can enable them and recover existing inline-image histories. Please distinguish a permanent fix from a temporary connection reset.
The affected work is being kept running. No private images, transcripts, raw logs, credentials, or local chat identifiers are attached.