macOS Desktop: image-heavy thread takes minutes to open because rollout JSONL embeds generated image payloads inline
What version of the Codex App are you using?
Codex Desktop 26.506.31421 on macOS. App bundle:
CFBundleShortVersionString:26.506.31421CFBundleVersion:2620- Bundle ID:
com.openai.codex - Session meta in rollout:
cli_version: 0.130.0-alpha.5,originator: Codex Desktop
What platform is your computer?
macOS 26.5 (25F71), Apple Silicon / arm64.
What issue are you seeing?
Opening one Codex Desktop thread for a local repo with many generated images made the Desktop app appear to crash or become unresponsive. It eventually opened after several minutes, but the thread was heavy enough that normal Desktop use became painful.
Local diagnosis shows the session trace stores full image bytes inline, even though the generated image files are also written separately under ~/.codex/generated_images/.
Measured local data for the affected thread:
~/.codex/sessions/2026/05/11/rollout-<thread-id>.jsonl:747 MB- JSONL record count:
2,164 - Matching
~/.codex/generated_images/<thread-id>/:82PNG files,240 MB 82generated images appear to be stored twice in the JSONL: once asevent_msg/payload.type == image_generation_end, and once asresponse_item/payload.type == image_generation_call164JSONL records contain multi-megabytepayload.resultbase64 PNG strings35additionalfunction_call_outputrecords contained embeddedinput_image.image_url: data:image/...;base64payloads191JSONL lines were larger than1 MB; the oversized lines accounted for most of the rollout file
Manual recovery confirmed the root cause. Redacting only embedded image payloads while preserving all JSONL records and metadata reduced the rollout file from 747 MB to 2.3 MB:
- replace
payload.resultforimage_generation_end/image_generation_callwith a short placeholder - replace nested
image_urlvalues beginning withdata:image/with a short placeholder - keep
saved_path, call ids, prompts, timestamps, and all other metadata intact - validate JSONL with
jq -e .
After this trim, the file still had the same 2,164 records and no JSONL line above 1 MB.
This looks related to, but not exactly the same observed platform, as:
- https://github.com/openai/codex/issues/22004
- https://github.com/openai/codex/issues/21232
- https://github.com/openai/codex/issues/21948
I am filing this as a macOS Desktop datapoint with exact local measurements. Feel free to close as duplicate if the intended fix is tracked elsewhere.
Steps to reproduce
- Use Codex Desktop on macOS.
- In one thread, generate dozens of images, enough to create many records with
payload.type == image_generation_endandpayload.type == image_generation_call. - Confirm the rollout JSONL grows into hundreds of MB because generated images are embedded as base64 in
payload.resultwhile also being saved under~/.codex/generated_images/<thread-id>/. - Close/reopen Codex Desktop or select that thread.
- Observe that opening the thread can freeze/hang the Desktop UI for minutes or make it appear to crash.
Expected behavior
Codex Desktop should stay responsive when opening image-heavy threads. Generated image bytes should not be duplicated inline in the session rollout if they are already stored as files, or the loader should lazy-load/stream/skip oversized binary payloads safely.
At minimum, Desktop should detect oversized image-heavy sessions, show a clear warning, and provide a built-in way to compact/trim embedded images without forcing users to manually edit ~/.codex/sessions.
Actual behavior
The Desktop app attempts to load/hydrate a hundreds-of-MB rollout file with many inline base64 image payloads, causing the UI to become unresponsive for minutes when opening the thread.
Privacy note
I intentionally omitted the raw rollout file, prompts, local username, full thread id, generated images, and repo contents from this public report. The important reproducible signal is the data shape and sizes above.
7 Comments
Additional local recovery note: replacing embedded image bytes with arbitrary placeholder strings is not enough for a compacted thread to continue. Codex replay/API validation still treats prior tool outputs as typed image values.
In this affected thread, changing
input_image.image_urlvalues from[trimmed ...]placeholders caused a 400 on the next send:A schema-valid compact form worked better locally: replace old
input_image.image_urldata URLs with a tiny validdata:image/png;base64,...URL, and replaceimage_generation_end/image_generation_callresultvalues with the tiny PNG's raw base64. The rollout stayed about2.3 MB, but no longer contained invalid placeholder image URLs.For an official compaction feature, it would be useful if Codex either omits old binary image tool outputs from replay in a schema-aware way, or substitutes typed minimal image references that still satisfy Responses API validation.
Follow-up correction from local recovery: the tiny 1x1 PNG substitute was still rejected on replay with
Invalid image in your last message.The compact shape that currently avoids local replay image validation is stricter:
function_call_output.outputvalues that containinput_imageitems into text-only outputs such as[omitted prior image tool output from compacted Codex session]image_generation_end/image_generation_callresultfields image-shaped, but use a real valid64x64PNG base64 substitute instead of a 1x1 imageWith that, the rollout remains compact (
~4.0 MBfor this thread), valid JSONL, has noinput_image, noimage_url, nodata:imagefields, and no JSONL line above1 MB.Adding a newer generated-image datapoint that matches this issue closely. Full root-crash details are in #22004: https://github.com/openai/codex/issues/22004#issuecomment-4887099344
Short version:
26.623.101652(CFBundleVersion=4674), macOS15.7.7, arm641,165,931,575bytes with only3,240JSONL records179generated PNGs existed as separate artifacts, but the rollout also had358inlineimage_generation_end/image_generation_callresultfields totaling1,138,720,392bytesRangeError: Invalid string lengthand a loggedthread/readJSON line of536,871,005bytesThe local repair shape that stayed JSONL-valid and schema-friendlier was:
image_generation_end/image_generation_callresultvalues with a small valid 64x64 PNG base64 string, not arbitrary textfunction_call_output.outputvalues containinginput_image/data:imageinto text-only omitted-output stringssaved_pathThat reduced the rollout to
6,096,679bytes, same3,240records, max line84,047bytes, zero rawdata:imagerecords, and zero invalid image-generation result records.Adding a current macOS storage-growth datapoint.
Environment:
Aggregate measurements:
Representative rollout:
This shows a storage problem even before one individual rollout reaches the sizes that cause UI hangs. Generated images are saved as files but substantial image payloads are still retained inline in durable session JSONL, while tool outputs and compaction can amplify the footprint.
The current open-source image-generation path saves the image and still retains result.clone() in ImageGenerationItem, the legacy event, and the generated tool output. The existing thread-resume redaction is response-only and explicitly leaves persisted rollout history unchanged.
Expected:
Adding a Windows Codex Desktop datapoint that reproduces the same durable-storage amplification.
Environment
26.721.4979.0Measurements
286PNG files /476.6 MiB28602,086.2 MiB989.5 MiB,986.6 MiB, and525.3 MiB4,587.7 MiB(4.48 GiB)2,027.5 MiB(1.98 GiB)The rollout family was about
9.6xthe size of the separately stored PNG artifacts. This is not intended as a pure image-duplication ratio because the rollouts also contain text and tool records, but it shows the resulting storage amplification.The PNG store itself contained no exact duplicate files. The large footprint instead appears in durable rollout records, where image payloads are retained inline in image-generation events, tool outputs, and compacted history.
The child-thread amplification portion of this observation is also relevant to #34268.
Proposed direction
Privacy
This analysis used file sizes, record types, encoded lengths, and SHA-256 hashes only. I am not attaching raw rollouts, prompts, image contents, local paths, usernames, project names, or thread IDs.
The 747 MB rollout with 164 multi-megabyte generated-image records is a very strong real-world oversized-payload case, especially because the thread became practically unusable on reopen.
I’m testing Codex Rescue’s bounded diagnosis against this exact persisted shape. It is local-first, does not decode or rewrite inline images, and leaves the original rollout byte-for-byte untouched. It also will not perform the schema substitutions you tested or claim to fix Desktop loading; verification remains fail-closed.
If you still have an untouched backup of the affected session, could you try:
pipx install codex-rescue==0.1.0a3codex-rescue sessionscodex-rescue doctor --latestSanitized diagnostic output is sufficient—please don’t publish the rollout, images, database, prompts, paths, or secrets.
https://github.com/shleder/codex-rescue
Reproduced on macOS with the unified ChatGPT/Codex desktop app 26.810.52044 (bundled codex-cli 0.148.0-alpha.9).
This looks like a current-version continuation failure related to this issue:
Sanitized log sequence:
The
turn/startrequest succeeds and other app-server/config/auth requests continue succeeding, so this does not appear to be a real network outage. The failure seems to be a mismatch between the persisted thread state and the renderer/app-server event routing, triggered or amplified by the image-heavy rollout.Expected: image-heavy historical threads should remain continuable, or the app should compact/lazy-load old image payloads and show a precise recovery error.
Actual: the existing thread cannot produce further assistant/tool output, while fresh threads work.
Privacy note: I intentionally omitted the raw rollout, thread ID, prompts, generated images, repository contents, username, and local paths.