codex - 💡(How to fix) Fix # Codex desktop main-process crash: `RangeError: Invalid string length` when loading sessions whose rollout JSONL exceeds V8's max string length [3 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openai/codex#22004Fetched 2026-05-11 03:21:14
View on GitHub
Comments
3
Participants
3
Timeline
10
Reactions
1
Timeline (top)
labeled ×6commented ×3cross-referenced ×1

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.

Error Message

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)

Root Cause

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.

Fix Action

Fix / Workaround

  1. 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.
  2. 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.
  3. Catch the RangeError at 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.
  4. 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.)
  5. 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)

  1. 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.
  2. 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.
  3. Catch the RangeError at 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.
  4. 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.)
  5. 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.

Code Example

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)

---

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)
RAW_BUFFERClick to expand / collapse

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.onStreamReadReadable.pushSocket.emit('data')Socket.onStdoutDataod.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

  1. 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).
  2. Continue in the same thread until C:\Users\<user>\.codex\sessions\<YYYY>\<MM>\<DD>\rollout-*.jsonl exceeds ~512 MB on disk. (In my case, ~300–500 images depending on dimensions.)
  3. Close Codex. Reopen.
  4. 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 / codex processes 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 / codex child 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)

  1. 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.
  2. 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.
  3. Catch the RangeError at 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.
  4. 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.)
  5. 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:

  1. End Task on all Codex / codex processes in Task Manager.
  2. In C:\Users\<user>\.codex\sessions\, locate the largest rollout-*.jsonl (sort by size). Anything >400 MB is a risk; anything >512 MB is a guaranteed crash.
  3. Move the file out of sessions/ to any other location.
  4. Edit C:\Users\<user>\.codex\session_index.jsonl and delete the line whose id matches the rollout's filename UUID. (Make a .bak first.)
  5. 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_*.sqlite in ~/.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.onStreamReadReadable.pushSocket.emit('data')Socket.onStdoutDataod.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

  1. 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).
  2. Continue in the same thread until C:\Users\<user>\.codex\sessions\<YYYY>\<MM>\<DD>\rollout-*.jsonl exceeds ~512 MB on disk. (In my case, ~300–500 images depending on dimensions.)
  3. Close Codex. Reopen.
  4. 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 / codex processes 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 / codex child 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)

  1. 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.
  2. 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.
  3. Catch the RangeError at 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.
  4. 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.)
  5. 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:

  1. End Task on all Codex / codex processes in Task Manager.
  2. In C:\Users\<user>\.codex\sessions\, locate the largest rollout-*.jsonl (sort by size). Anything >400 MB is a risk; anything >512 MB is a guaranteed crash.
  3. Move the file out of sessions/ to any other location.
  4. Edit C:\Users\<user>\.codex\session_index.jsonl and delete the line whose id matches the rollout's filename UUID. (Make a .bak first.)
  5. 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_*.sqlite in ~/.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

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

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.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

codex - 💡(How to fix) Fix # Codex desktop main-process crash: `RangeError: Invalid string length` when loading sessions whose rollout JSONL exceeds V8's max string length [3 comments, 3 participants]