image_gen regression in 0.140.0: valid generated image is not saved when status remains generating
What version of Codex CLI is running?
0.140.0
What subscription do you have?
pro
Which model were you using?
gpt-5.4-mini
What platform is your computer?
Microsoft Windows NT 10.0.26200.0 x64
What terminal emulator and version are you using (if applicable)?
_No response_
Codex doctor report
What issue are you seeing?
Summary
In Codex CLI 0.140.0, image_gen can return a valid generated PNG payload but never save it to the generated images directory.
The issue appears to be caused by a new persistence gate added in codex-rs/core/src/stream_events_utils.rs: image generation results are now only persisted when image_item.status == "completed".
However, I observed a successful image generation response where:
statuswas still"generating"resultcontained a non-empty base64 payload- the payload decoded to a valid PNG
- no file was written under
<codex_home>/generated_images/<thread_id>/<call_id>.png
Rolling back to 0.139.0 made image saving work again.
Observed behavior
A session produced an image_generation_call like this, with identifiers anonymized:
type: image_generation_call
id: <image-call-id>
status: generating
result: <non-empty base64 PNG>
The result field was valid:
decoded bytes: >1 MB
PNG signature: 89 50 4E 47 0D 0A 1A 0A
But the expected file was not created:
<codex_home>/generated_images/<thread-id>/<image-call-id>.png
What steps can reproduce the bug?
Use $image_gen to create an image using codex 0.140.0
What is the expected behavior?
If an image generation item contains a valid non-empty image result, Codex should persist it to the generated images directory, even if the status is still "generating".
Alternatively, the status should be normalized to "completed" before the persistence path runs.
Suspected regression
This change in codex-rs/core/src/stream_events_utils.rs appears to be the cause:
if let TurnItem::ImageGeneration(image_item) = &mut *turn_item
&& image_item.status == "completed"
{
persist_image_generation_item(sess, turn_context, image_item).await;
}
Before this change, Codex attempted to persist every ImageGeneration item. In 0.140.0, if a successful result arrives with status: "generating", persistence is skipped entirely.
Additional information
Suggested fix
Persist image generation results based on whether there is image data, not only on the status string.
For example:
if let TurnItem::ImageGeneration(image_item) = &mut *turn_item
&& !image_item.result.trim().is_empty()
{
persist_image_generation_item(sess, turn_context, image_item).await;
}
Or, if preserving the completed-status behavior is important:
if let TurnItem::ImageGeneration(image_item) = &mut *turn_item
&& (image_item.status == "completed" || !image_item.result.trim().is_empty())
{
persist_image_generation_item(sess, turn_context, image_item).await;
}
This should still avoid saving failed image generations, because failed items appear to have an empty result.
Suggested regression test
Add a test where a ResponseItem::ImageGenerationCall has:
status: "generating".to_string(),
result: "Zm9v".to_string(), // or valid PNG base64
Then assert that finalize_turn_item or the relevant response handling path persists the image and sets saved_path.
The important case is:
- status is not
"completed" - result is non-empty valid base64
- persistence should still happen
Environment
- Codex CLI:
0.140.0 - Platform: Windows
- Regression:
0.139.0saves successfully;0.140.0does not in the case above
17 Comments
I can reproduce the same regression on macOS with an npm-managed Codex CLI.
Environment:
Observed behavior on 0.140.0:
After downgrading:
~/.codex/generated_images/<thread_id>/<image_id>.png
Example saved path after rollback:
.codex/generated_images/xxxx/xxxx.png
This makes the regression appear specific to 0.140.0 rather than a local permissions or directory setup issue.
Confirming this on Linux x86_64 as well (not Windows-specific):
codex-cli 0.139.0: built-inimage_genfrom the CLI writes the PNG to~/.codex/generated_images/<session-id>/ig_<id>.png(verified with thenotifyhook disabled, so it's genuine native behavior).codex-cli 0.140.0: same prompt/flags, nothing written to disk anywhere (neithergenerated_imagesnor CWD).In the 0.140.0 rollout the
image_generation_callitem carries a full valid PNG base64 inresultwhile"status":"generating", which matches your root-cause analysis of thestatus == "completed"gate instream_events_utils.rs. Auth was ChatGPT sign-in (noOPENAI_API_KEY), built-in tool path. Downgrading to 0.139.0 restores saving.Confirming this (codex cli inside a Docker Ubuntu 24.04 sandbox container). I literally had to tell Codex CLI to invoke another codex sub-instance and retrieve the image from the session logs despite the status saying generating. This is a very unpleasant 0.140.0 bug
We’re seeing what looks like the same regression in our environment.
Environment:
codex-cli 0.140.0-alpha.1926.611.61753/ build4008CODEX_HOMEeffectively/Users/billyzhang/.codex(~/.codexexists and is used for config/logs/plugins)Observed behavior:
image_gencalls complete successfully and the image appears inline in the Codex conversation./Users/billyzhang/.codex/generated_images.png/jpg/jpeg/webp/heicfiles under both~/.codexand/Users/billyzhangfound no generated artifact.So from the user-visible side this matches the “generation succeeds but no persisted file is available” behavior described here.
I can confirm the same regression on Linux with Codex CLI
0.140.0.Observed locally:
image_generation_end/image_generation_callrecords contain a non-empty PNG base64result."generating".saved_pathis absent and no PNG is written under~/.codex/generated_images/<thread-id>/.I also checked the current upstream state:
rust-v0.140.0still gates persistence onimage_item.status == "completed".mainappears to persist image generation items based on a non-emptyresultinstead.So the behavior appears fixed on
main, but absent fromrust-v0.140.0; a release containing this main-branch change would resolve the observed regression.One possible follow-up test, if useful, would be a focused regression case in
codex-rs/core/src/stream_events_utils_tests.rsthat passes anImageGenerationCallwithstatus: "generating"and a non-empty base64resultthrough the finalization path, then asserts thatsaved_pathis set and the generated image file is written.Confirming the same persistence failure on Windows / Codex Desktop.
Environment and evidence:
cli_version = 0.140.0-alpha.19for the affected thread.image_gencompleted and rendered inline in the conversation.image_generation_end/image_generation_callentries with:resultstatus: "generating"saved_path%USERPROFILE%\.codex\generated_images\<thread-id>\.cli_version = 0.137.0-alpha.4did includeevent_msg.payload.saved_path, and the referenced generated image file existed.This matches the suspected status-gate regression: the image payload is present and valid, but persistence is skipped while the item remains in
generatingstatus.I'm seeing this in the macOS Codex Desktop App now since upgrading to
26.611.61753.I can reproduce this on another Windows install of Codex CLI 0.140.0. Adding details here rather than opening a duplicate because the symptom matches this issue closely.
Repro summary
In a fresh Codex session, after verifying the image generation prerequisite, the agent attempted to generate a recipe hero image from a prompt file and save it as a project PNG.
Observed behavior:
~/.codex/generated_images.%TEMP%or the target project folder.The failed workflow was essentially:
Expected behavior:
~/.codex/generated_images/<thread>/<call>.png, or expose enough result metadata for the agent to write the target file.Actual behavior:
Local checks
codex doctorsummarycodex doctor --jsoncompleted withoverallStatus: ok. Relevant redacted fields:No doctor checks failed. This looks consistent with the persistence gate described in the issue: generation can succeed visibly, but the artifact persistence path does not leave a usable local PNG for the agent to move or copy.
Can confirm on 0.140.0 on macOS also. Materialized in a funny way, asked it to generate an image and the results were like stick figures because Codex noticed the generations weren't working and used a Python PIL script to attempt to produce the requested image instead.
I’m seeing the same regression in Codex desktop app 26.611.62324 (4028) on macOS. Built-in image_gen produces image_generation_call entries with status="generating" and a non-empty valid PNG base64 result, but no file is written to ~/.codex/generated_images/<thread-id>/<call-id>.png and no saved_path is recorded.
Expected: generated image is persisted under ~/.codex/generated_images/.
Actual: image exists only in the session JSONL result payload.
Same issue with latest
0.141.0. Downgrading to0.139.0restores image_gen capability.Confirming the same regression on macOS (Apple Silicon), codex-cli 0.140.0 installed via Homebrew cask, ChatGPT auth (no
OPENAI_API_KEY), modelgpt-5.5,image_generationfeature reportedstable true.image_genruns but nothing is persisted under~/.codex/generated_images/<thread_id>/. The last successfully saved session dir on this machine is from 2026-06-15, and the 0.140.0 cask landed 2026-06-16 (/opt/homebrew/Caskroom/codex/0.140.0, binary mtimeJun 16 05:51). The break lines up exactly with the upgrade window described here.Two distinct downstream symptoms in
codex exec --jsonheadless runs, both consistent with thestatus == "completed"persistence gate:image_gen, the inline image appears but no PNG lands in the session dir, so anything readinggenerated_images/finds nothing.referenced_image_paths), the model notices the generation didn't land and falls back to hand-writing a ~150-line Python/PIL script (rounded rects + grain texture) to fake the requested image. This matches @peterc's "stick figures via PIL" observation — it's reproducible, not a one-off.+1 for persisting whenever
resultis non-empty regardless ofstatus, per the suggested fix. Downgrading to0.139.0is the only thing restoring saved artifacts right now (and per a comment above,0.141.0still carries the bug).And now the recent codex app requires 0.141.0 on remote hosts, so image_gen became completely unusable in codex app
I can reproduce the same failure on Codex CLI
0.141.0on Linux x64.Observed in the rollout transcript:
The
resultpayload decodes successfully and starts with the PNG signature:No file is written under the expected generated-images path for the thread/call. This still matches the suspected regression: persistence is gated on
image_item.status == "completed", but the backend response can carry a valid image payload while the status remains"generating".So this is not limited to
0.140.0or Windows; it is still present in0.141.0on Linux.Present on Linux 0.141.0 too.
Same on Windows 0.141.0
It seems to have been fixed by #28656. Tested with 0.142.0 and seems alright, so I'm closing this.