Summary
Codex desktop appears to persist image-producing tool output inline into replayable session history, especially as function_call_output items containing input_image payloads with data:image/...;base64,... content.
After enough of these accumulate, the thread can become unstable and start failing on later turns with:
This also appears likely to inflate model input usage for the affected thread because the replay payload becomes extremely large.
User-visible symptoms
- A thread works normally for a while, then later starts failing with:
- The agent stops mid-session or fails on later
continue attempts.
- Once a thread reaches this state, it may keep failing repeatedly.
- The affected thread/session becomes extremely large.
What I found locally
I inspected saved session JSONL data under ~/.codex/sessions/... and found many oversized function_call_output entries containing embedded inline image payloads such as:
type: "input_image"
image_url: "data:image/png;base64,..."
These image payloads are being persisted directly into replayable session history rather than stored out-of-line.
In the affected thread I observed:
- repeated
event_msg errors with:
- many very large
function_call_output records containing base64 images
- very large cumulative input-token counters in the same thread
- app-state telemetry showing very large delta-byte growth around the same period
Likely root cause
The desktop app seems to serialize tool screenshots inline into session state.
A strong lead is in the bundled browser-use plugin code shipped with the app bundle. In the installed app I found code in both:
/Applications/Codex.app/Contents/Resources/plugins/openai-bundled/plugins/browser-use/scripts/browser-client.mjs
/Applications/Codex.app/Contents/Resources/plugins/openai-bundled/plugins/chrome/scripts/browser-client.mjs
that converts screenshot buffers into inline data URLs before emitting them:
processImage:t=>{
if(!Buffer.isBuffer(t)) throw new Error(...);
return `data:image/jpeg;base64,${t.toString("base64")}`
}
That means screenshot-heavy tool output can enter replayable thread state as huge inline strings.
Why this matters
This is more than a display bug:
- it can permanently poison a thread
- it can trigger replay/resume failures with
400 / {"detail":"Bad Request"}
- it likely wastes context/token budget if these payloads are replayed or summarized into later requests
- it probably affects any user doing longer sessions with image-heavy tools (Computer Use / browser-use / screenshot-producing tools)
Repro idea
- Start a long Codex desktop thread.
- Use Computer Use / browser-use or another screenshot-producing tool repeatedly.
- Continue the same thread many times.
- Inspect the saved session JSONL and observe large
input_image / data:image/...;base64,... payloads inside function_call_output.
- Eventually the thread starts failing with:
Expected behavior
Tool images should not be embedded as large base64 strings in replayable session history.
Instead, Codex should:
- store image blobs out-of-line
- persist only a file/blob reference or lightweight handle
- cap / summarize oversized tool outputs before they enter replayable thread state
- reject or sanitize replay-hostile payloads during persistence and/or resume
Actual behavior
Large inline base64 screenshots are persisted directly in function_call_output, and the thread later fails with:
Suggested fix
- externalize tool images to blob/file storage before persistence
- persist only lightweight references in session history
- add hard caps/truncation for replayed tool output
- prevent megabyte-scale inline payloads from being stored in replayable thread context
- consider a repair/sanitization path for already-poisoned sessions
Notes
I also suspect this bug may contribute to inflated subscription/token usage for affected threads because the stored payload becomes massive and may be replayed to the model on later turns.
If helpful, I can provide a sanitized example session structure showing the oversized function_call_output / input_image pattern without exposing private data.
Summary
Codex desktop appears to persist image-producing tool output inline into replayable session history, especially as
function_call_outputitems containinginput_imagepayloads withdata:image/...;base64,...content.After enough of these accumulate, the thread can become unstable and start failing on later turns with:
{"detail":"Bad Request"}This also appears likely to inflate model input usage for the affected thread because the replay payload becomes extremely large.
User-visible symptoms
{"detail":"Bad Request"}continueattempts.What I found locally
I inspected saved session JSONL data under
~/.codex/sessions/...and found many oversizedfunction_call_outputentries containing embedded inline image payloads such as:type: "input_image"image_url: "data:image/png;base64,..."These image payloads are being persisted directly into replayable session history rather than stored out-of-line.
In the affected thread I observed:
event_msgerrors with:{"detail":"Bad Request"}function_call_outputrecords containing base64 imagesLikely root cause
The desktop app seems to serialize tool screenshots inline into session state.
A strong lead is in the bundled browser-use plugin code shipped with the app bundle. In the installed app I found code in both:
/Applications/Codex.app/Contents/Resources/plugins/openai-bundled/plugins/browser-use/scripts/browser-client.mjs/Applications/Codex.app/Contents/Resources/plugins/openai-bundled/plugins/chrome/scripts/browser-client.mjsthat converts screenshot buffers into inline data URLs before emitting them:
That means screenshot-heavy tool output can enter replayable thread state as huge inline strings.
Why this matters
This is more than a display bug:
400/{"detail":"Bad Request"}Repro idea
input_image/data:image/...;base64,...payloads insidefunction_call_output.{"detail":"Bad Request"}Expected behavior
Tool images should not be embedded as large base64 strings in replayable session history.
Instead, Codex should:
Actual behavior
Large inline base64 screenshots are persisted directly in
function_call_output, and the thread later fails with:{"detail":"Bad Request"}Suggested fix
Notes
I also suspect this bug may contribute to inflated subscription/token usage for affected threads because the stored payload becomes massive and may be replayed to the model on later turns.
If helpful, I can provide a sanitized example session structure showing the oversized
function_call_output/input_imagepattern without exposing private data.