# Codex desktop main-process crash: `RangeError: Invalid string length` when loading sessions whose rollout JSONL exceeds V8's max string length
What version of the Codex App are you using (From “About Codex” dialog)?
- OS: Windows 11 (x64) - Install: Microsoft Store —
C:\Program Files\WindowsApps\OpenAI.Codex_<version>_x64__2p2nqsd0c76g0\app\- Versions reproduced on: 26.506.2212.0 and 26.506.3741.0 (auto-update did not fix) - Config:model = "gpt-5.5",model_reasoning_effort = "xhigh",windows.sandbox = "elevated"
What subscription do you have?
Pro
What platform is your computer?
Windows 11
What issue are you seeing?
Codex desktop main-process crash: RangeError: Invalid string length when loading sessions whose rollout JSONL exceeds V8's max string length
Severity
High. Crash blocks startup. The error is shown in a modal dialog that cannot be dismissed (clicking OK reopens it / Codex is unresponsive); the only way out is to kill every Codex process via Task Manager. Once a session's rollout file passes ~512 MB on disk, opening Codex hangs / crashes 100% of the time. The session — and any work in progress in it — becomes unreachable from the UI.
Environment
- OS: Windows 11 (x64)
- Install: Microsoft Store —
C:\Program Files\WindowsApps\OpenAI.Codex_<version>_x64__2p2nqsd0c76g0\app\ - Versions reproduced on: 26.506.2212.0 and 26.506.3741.0 (auto-update did not fix)
- Config:
model = "gpt-5.5",model_reasoning_effort = "xhigh",windows.sandbox = "elevated"
Summary
The Electron main process consumes stdout from a child process (the Codex primary runtime) and concatenates the data into a single JavaScript string in the od.write aggregator. When the cumulative string passes V8's max single-string length (~512 MB on 64-bit, 2^29 - 24 bytes for one-byte strings), String.prototype.concat / += throws RangeError: Invalid string length. The exception is uncaught in the main process, so Electron surfaces the generic "A JavaScript error occurred in the main process" dialog and the app never finishes initializing.
The trigger in practice is a session whose rollout file ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-*.jsonl has grown past ~512 MB. This is easy to hit when a single thread is used heavily for image generation, because each generated image is embedded as base64 (≈1–2 MB per image) directly inline in the rollout JSONL. After ~300–500 images in one thread, the file crosses the limit.
Stack trace (verbatim from the error dialog)
Uncaught Exception:
RangeError: Invalid string length
at od.write (C:\Program Files\WindowsApps\OpenAI.Codex_26.506.3741.0_x64__2p2nqsd0c76g0\app\resource...:7111)
at Socket.onStdoutData (C:\Program Files\WindowsApps\OpenAI.Codex_26.506.3741.0_x64__2p2nqsd0c76g0\app\resource...:3865)
at Socket.emit (node:events:508:28)
at addChunk (node:internal/streams/readable:563:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:514:3)
at Readable.push (node:internal/streams/readable:394:5)
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)
The trace path is unambiguous: Pipe.onStreamRead → Readable.push → Socket.emit('data') → Socket.onStdoutData → od.write. The crash is not in plugin code, model code, or rendering — it is in the stdout aggregator on the main process, attempting to grow a string past V8's limit.
Reproduction
- Use Codex on Windows. In a single thread, run an image-generation workflow that embeds base64 image data into the session rollout (any image-gen plugin will do — the trigger is base64 size, not the source).
- Continue in the same thread until
C:\Users\<user>\.codex\sessions\<YYYY>\<MM>\<DD>\rollout-*.jsonlexceeds ~512 MB on disk. (In my case, ~300–500 images depending on dimensions.) - Close Codex. Reopen.
- The "A JavaScript error occurred in the main process" dialog appears with the stack trace above. Clicking OK does nothing useful; the only way to recover is to End Task on all
Codex/codexprocesses via Task Manager.
Reproduces 100% on my machine. I have hit it twice now in two weeks; six rollouts in my sessions/ folder grew past the limit. Sizes I observed: 506.8 MB, 786.7 MB, 963.5 MB, 1050.3 MB, 1050 MB, 1601 MB.
Expected behavior
Either:
- Codex loads sessions of arbitrary size successfully (preferred — see fix #1 below), or
- Codex detects the oversized rollout, refuses to load that one session with a clear message, and continues to start normally so the user retains access to all other threads.
Actual behavior
- Main process crashes during startup with the stack above.
- Modal error dialog cannot be dismissed.
- Codex is fully unresponsive; multiple
Codex/codexchild processes remain running (in my last incident, six processes, ~3.4 GB RSS combined). - All threads — not just the bloated one — are inaccessible until the user manually moves the offending file out of
sessions/.
Root cause analysis
V8 caps single-string length at 2^29 - 24 bytes (~512 MB) for one-byte strings, halved for two-byte strings. Reference: v8/include/v8-primitive.h kMaxLength.
The Socket.onStdoutData handler in Codex's main process accumulates the runtime subprocess's stdout into a single string buffer (visible in the trace as od.write). For sessions with rollout JSONL >512 MB, the subprocess streams the file's contents through stdout (likely as part of a "load this session" request), and the cumulative buffer overflows V8's limit.
The deeper design issue: the rollout JSONL format embeds base64 image data inline. Generated images are typically also written to ~/.codex/generated_images/, so the same bytes are duplicated in two places — but only the JSONL embed is what triggers the crash, because that's what gets pumped through stdout on session load.
Suggested fixes (in order of robustness)
- Stream-parse rollouts. JSONL is line-delimited; the runtime should emit one record per chunk and the main process should parse incrementally rather than buffering the entire file as one string. This eliminates the V8 limit as a constraint entirely.
- Cap and chunk the stdout aggregator. In
od.write, when the buffer crosses some threshold (say 256 MB), flush the accumulated content to the consumer and reset, instead of growing forever. JSON message framing (length-prefixed or NDJSON) on the IPC channel would make this trivial. - Catch the
RangeErrorat the boundary and surface a useful error to the user ("Session 'X' could not be loaded — file too large, see <link>") rather than crashing the main process. This alone would unblock users and let them at least see/use other threads. - Stop embedding image bytes in rollouts. Store images only in
generated_images/and reference them from the JSONL by path or content hash. Rollouts would shrink ~99% for image-gen workflows. (This is the right long-term fix; users who generate hundreds of images in one thread will keep producing >512 MB rollouts otherwise.) - Add a periodic rollout-size warning in the UI ("This thread's transcript is 380 MB and may not load on next launch — start a new thread or contact support"). Soft mitigation but very cheap to add.
Workaround (for users hitting this now)
Until a fix ships, users can recover access by manually archiving the oversized rollout:
- End Task on all
Codex/codexprocesses in Task Manager. - In
C:\Users\<user>\.codex\sessions\, locate the largestrollout-*.jsonl(sort by size). Anything >400 MB is a risk; anything >512 MB is a guaranteed crash. - Move the file out of
sessions/to any other location. - Edit
C:\Users\<user>\.codex\session_index.jsonland delete the line whoseidmatches the rollout's filename UUID. (Make a.bakfirst.) - Reopen Codex — it should start cleanly. The archived thread is no longer in the UI but the data is preserved on disk.
Additional context
logs_*.sqlitein~/.codex/also grew to 2+ GB on my machine, contributing to slow startup but not the crash itself. Some kind of log rotation cap would be welcome.- Orphan
..codex-global-state.json.tmp-<timestamp>-<uuid>files accumulate in~/.codex/after crashes (the atomic-write tempfile is never cleaned up). Minor, but worth a sweep on startup.
What steps can reproduce the bug?
Codex desktop main-process crash: RangeError: Invalid string length when loading sessions whose rollout JSONL exceeds V8's max string length
Severity
High. Crash blocks startup. The error is shown in a modal dialog that cannot be dismissed (clicking OK reopens it / Codex is unresponsive); the only way out is to kill every Codex process via Task Manager. Once a session's rollout file passes ~512 MB on disk, opening Codex hangs / crashes 100% of the time. The session — and any work in progress in it — becomes unreachable from the UI.
Environment
- OS: Windows 11 (x64)
- Install: Microsoft Store —
C:\Program Files\WindowsApps\OpenAI.Codex_<version>_x64__2p2nqsd0c76g0\app\ - Versions reproduced on: 26.506.2212.0 and 26.506.3741.0 (auto-update did not fix)
- Config:
model = "gpt-5.5",model_reasoning_effort = "xhigh",windows.sandbox = "elevated"
Summary
The Electron main process consumes stdout from a child process (the Codex primary runtime) and concatenates the data into a single JavaScript string in the od.write aggregator. When the cumulative string passes V8's max single-string length (~512 MB on 64-bit, 2^29 - 24 bytes for one-byte strings), String.prototype.concat / += throws RangeError: Invalid string length. The exception is uncaught in the main process, so Electron surfaces the generic "A JavaScript error occurred in the main process" dialog and the app never finishes initializing.
The trigger in practice is a session whose rollout file ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-*.jsonl has grown past ~512 MB. This is easy to hit when a single thread is used heavily for image generation, because each generated image is embedded as base64 (≈1–2 MB per image) directly inline in the rollout JSONL. After ~300–500 images in one thread, the file crosses the limit.
Stack trace (verbatim from the error dialog)
Uncaught Exception:
RangeError: Invalid string length
at od.write (C:\Program Files\WindowsApps\OpenAI.Codex_26.506.3741.0_x64__2p2nqsd0c76g0\app\resource...:7111)
at Socket.onStdoutData (C:\Program Files\WindowsApps\OpenAI.Codex_26.506.3741.0_x64__2p2nqsd0c76g0\app\resource...:3865)
at Socket.emit (node:events:508:28)
at addChunk (node:internal/streams/readable:563:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:514:3)
at Readable.push (node:internal/streams/readable:394:5)
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)
The trace path is unambiguous: Pipe.onStreamRead → Readable.push → Socket.emit('data') → Socket.onStdoutData → od.write. The crash is not in plugin code, model code, or rendering — it is in the stdout aggregator on the main process, attempting to grow a string past V8's limit.
Reproduction
- Use Codex on Windows. In a single thread, run an image-generation workflow that embeds base64 image data into the session rollout (any image-gen plugin will do — the trigger is base64 size, not the source).
- Continue in the same thread until
C:\Users\<user>\.codex\sessions\<YYYY>\<MM>\<DD>\rollout-*.jsonlexceeds ~512 MB on disk. (In my case, ~300–500 images depending on dimensions.) - Close Codex. Reopen.
- The "A JavaScript error occurred in the main process" dialog appears with the stack trace above. Clicking OK does nothing useful; the only way to recover is to End Task on all
Codex/codexprocesses via Task Manager.
Reproduces 100% on my machine. I have hit it twice now in two weeks; six rollouts in my sessions/ folder grew past the limit. Sizes I observed: 506.8 MB, 786.7 MB, 963.5 MB, 1050.3 MB, 1050 MB, 1601 MB.
Expected behavior
Either:
- Codex loads sessions of arbitrary size successfully (preferred — see fix #1 below), or
- Codex detects the oversized rollout, refuses to load that one session with a clear message, and continues to start normally so the user retains access to all other threads.
Actual behavior
- Main process crashes during startup with the stack above.
- Modal error dialog cannot be dismissed.
- Codex is fully unresponsive; multiple
Codex/codexchild processes remain running (in my last incident, six processes, ~3.4 GB RSS combined). - All threads — not just the bloated one — are inaccessible until the user manually moves the offending file out of
sessions/.
Root cause analysis
V8 caps single-string length at 2^29 - 24 bytes (~512 MB) for one-byte strings, halved for two-byte strings. Reference: v8/include/v8-primitive.h kMaxLength.
The Socket.onStdoutData handler in Codex's main process accumulates the runtime subprocess's stdout into a single string buffer (visible in the trace as od.write). For sessions with rollout JSONL >512 MB, the subprocess streams the file's contents through stdout (likely as part of a "load this session" request), and the cumulative buffer overflows V8's limit.
The deeper design issue: the rollout JSONL format embeds base64 image data inline. Generated images are typically also written to ~/.codex/generated_images/, so the same bytes are duplicated in two places — but only the JSONL embed is what triggers the crash, because that's what gets pumped through stdout on session load.
Suggested fixes (in order of robustness)
- Stream-parse rollouts. JSONL is line-delimited; the runtime should emit one record per chunk and the main process should parse incrementally rather than buffering the entire file as one string. This eliminates the V8 limit as a constraint entirely.
- Cap and chunk the stdout aggregator. In
od.write, when the buffer crosses some threshold (say 256 MB), flush the accumulated content to the consumer and reset, instead of growing forever. JSON message framing (length-prefixed or NDJSON) on the IPC channel would make this trivial. - Catch the
RangeErrorat the boundary and surface a useful error to the user ("Session 'X' could not be loaded — file too large, see <link>") rather than crashing the main process. This alone would unblock users and let them at least see/use other threads. - Stop embedding image bytes in rollouts. Store images only in
generated_images/and reference them from the JSONL by path or content hash. Rollouts would shrink ~99% for image-gen workflows. (This is the right long-term fix; users who generate hundreds of images in one thread will keep producing >512 MB rollouts otherwise.) - Add a periodic rollout-size warning in the UI ("This thread's transcript is 380 MB and may not load on next launch — start a new thread or contact support"). Soft mitigation but very cheap to add.
Workaround (for users hitting this now)
Until a fix ships, users can recover access by manually archiving the oversized rollout:
- End Task on all
Codex/codexprocesses in Task Manager. - In
C:\Users\<user>\.codex\sessions\, locate the largestrollout-*.jsonl(sort by size). Anything >400 MB is a risk; anything >512 MB is a guaranteed crash. - Move the file out of
sessions/to any other location. - Edit
C:\Users\<user>\.codex\session_index.jsonland delete the line whoseidmatches the rollout's filename UUID. (Make a.bakfirst.) - Reopen Codex — it should start cleanly. The archived thread is no longer in the UI but the data is preserved on disk.
Additional context
logs_*.sqlitein~/.codex/also grew to 2+ GB on my machine, contributing to slow startup but not the crash itself. Some kind of log rotation cap would be welcome.- Orphan
..codex-global-state.json.tmp-<timestamp>-<uuid>files accumulate in~/.codex/after crashes (the atomic-write tempfile is never cleaned up). Minor, but worth a sweep on startup.
What is the expected behavior?
_No response_
Additional information
_No response_
6 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Related macOS evidence: my failing thread is an 825MB rollout, but I saw a dropped 405MB IPC frame rather than
RangeError. Same underlying limit class: full rollout/thread state is being aggregated into huge Electron/JS payloads. Even before a hard V8 string-length crash, the app becomes unusable; it needs size gates and paged/tail-only loading.Follow-up / PR offer: I read the contribution docs and understand external PRs are invitation-only. If the team thinks this direction fits, I’d be happy to take a stab at an invited PR for the open-source app-server side.
Conceptually, the fix I’d propose is:
thread/read,thread/resume, and stream-state snapshots cannot produce 100MB+ payloadsThe desktop side still needs closed-code changes, but the app-server can provide the safe bounded contract and fail gracefully when a client asks for full hydration of an oversized rollout.
I hit the same failure class on macOS Codex Desktop.
Environment
26.513.31313~/.codex/sessions/.../rollout-2026-05-15T08-21-11-019e2a82-ba83-7333-bac7-954d24293676.jsonl1,368,538,366bytes (~1.37 GB)23,442JSONL recordsCrash
Electron main-process alert:
Observed local behavior
thread/readreturned quickly for that conversation.thread/resumecompletion logged for the affected conversation.Rollout contents / workaround evidence
The bloat was mostly plain tool/result payloads, not encrypted content:
event_msg/mcp_tool_call_end: ~698 MBresponse_item/function_call_output: ~648 MBencrypted_content: ~3.6 MB total, max ~11 KBA local repair that redacted only oversized plain tool-result strings and replaced oversized inline
image_urldata with a tiny validdata:image/png;base64,...placeholder reduced the rollout to71,069,050bytes. The repaired JSONL kept the same23,442records, had no lines over 1 MB, and preserved encrypted-content count/hash exactly.Expected behavior: Desktop should not crash the Electron main process on a single oversized local session. It should stream/chunk large resume payloads, cap/summarize oversized tool outputs, or fail that one session with a recoverable error while keeping the rest of Desktop usable.
Additional macOS reproduction evidence for the same failure class.
Environment
26.608.12217(CFBundleVersion=3722)codex-cli 0.138.0-alpha.726.4.1build25E253, Apple Silicon /arm64liarsdiceproject019ea61c-c900-7980-a2b6-4501d8344757~/.codex/sessions/2026/06/08/rollout-2026-06-08T00-22-44-019ea61c-c900-7980-a2b6-4501d8344757.jsonl1,449,517,542bytes (~1.35 GiB),6,430JSONL recordsThe thread was a long-running image asset generation/review workflow. The final goal usage reported by Codex was about
7,569,355tokens. It generated/reviewed many image asset candidates, so the rollout grew very large.Crash dialog
Local observations
Socket.onStdoutData -> *.writepath described in this issue.RangeErrortext, and no new macOS crash report was found under~/Library/Logs/DiagnosticReports, so the visible evidence was primarily the Electron uncaught exception dialog plus the oversized rollout.~/Library/Logs/com.openai.codex/2026/06/11/.Expected behavior
Same as the original report: Codex Desktop should stream/chunk/cap oversized stdout/session payloads or fail only the affected thread with a recoverable error. A single oversized local rollout should not be able to crash the Electron main process.
Adding another macOS Desktop reproduction on a newer build, with local repair measurements. This one came from Codex Desktop built-in image generation rather than Computer Use.
Environment:
26.623.101652(CFBundleVersion=4674)15.7.7(24G720),arm64Crash / log evidence:
thread/readresponse crossing the practical V8/string boundary:Affected rollout stats before repair:
Important duplication detail: each generated image was present once as
event_msg/image_generation_end.resultand once asresponse_item/image_generation_call.result, while also being saved as a PNG artifact under the local generated-images directory.Local recovery that made the rollout small and parseable again:
payload.resultforimage_generation_end/image_generation_callwith a small valid 64x64 PNG base64 string, not an arbitrary text placeholder.17oldfunction_call_output.outputvalues containinginput_image/data:imagecontent into text-only omission strings.saved_path, and normal text records.After repair:
This supports the same root cause already described here: Desktop/app-server should not build full
thread/read/ resume / stream-state payloads that include historical image bytes, and rollout persistence should not store generated image bytes inline and duplicated across event and response surfaces. A built-in repair path that externalizes or schema-safely omits old image payloads would have recovered this thread without manual JSONL surgery.