Windows app: pasted clipboard images spin forever in history after Temp files are deleted
What version of the Codex App are you using (From “About Codex” dialog)?
26.707.8168.0
What subscription do you have?
Paid ChatGPT subscription (exact tier not included in this report).
What platform is your computer?
Microsoft Windows NT 10.0.26200.8655 x64 (Windows 11 25H2)
What issue are you seeing?
Images pasted from the Windows clipboard are processed successfully when the message is sent, but older images in the same Codex Desktop thread later display an infinite loading spinner.
A local inspection of the affected rollout JSONL shows two representations of each pasted image:
- The
response_itemmessage contains an embeddedinput_imagewith a completedata:image/png;base64,...URL. - The corresponding
event_msg.user_messagecontains only alocal_imagesentry pointing to:
C:\Users\<user>\AppData\Local\Temp\codex-clipboard-<uuid>.png
In the affected thread:
- 17 unique clipboard images were sent.
- All 17 have embedded
data:imagecontent in the rollout JSONL. - 16 of the 17 referenced
codex-clipboard-*.pngTemp files no longer exist. - The only image whose Temp file still exists is the newest image.
- The missing historical images show an infinite spinner in the UI.
- The model successfully processed the images at send time, so this is not an upload or inference failure.
This strongly suggests that the history renderer uses event_msg.payload.local_images paths and does not fall back to the already persisted embedded image data when the temporary clipboard files have been cleaned up.
No API gateway, account, or inference error is involved.
What steps can reproduce the bug?
- Open the Codex Windows desktop app.
- Paste a screenshot from the clipboard into a thread.
- Send the message and confirm that Codex can process the image.
- Repeat with several screenshots.
- Restart Codex and/or allow the Windows Temp directory to be cleaned.
- Reopen the thread and scroll to the older pasted screenshots.
- Observe that the image placeholders spin indefinitely when their
codex-clipboard-*.pngfiles no longer exist.
Diagnostic confirmation:
- Inspect the rollout JSONL under
~/.codex/sessions/. - The message has embedded
input_imageBase64 data, but the UI-facing event retains a path under%LOCALAPPDATA%\Temp. - Delete or lose that Temp file, then reopen the thread.
What is the expected behavior?
Pasted image attachments should remain visible in thread history after restarting the app or after Windows cleans the Temp directory.
The app should either:
- copy clipboard images to durable app storage before persisting the message,
- render from the embedded image data already stored in the rollout, or
- show a clear missing-attachment error instead of an infinite spinner.
Additional information
The image data appears recoverable from the rollout JSONL, so the underlying content has not been lost. The failure is in attachment persistence/history rendering.
The affected paths and thread identifiers have been redacted. A screenshot of the spinner and additional redacted diagnostics can be provided if needed.
3 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
A merged implementation in a separate Codex companion client provides a concrete version of the durable-storage fix proposed here.
grtninja/PennyGPT-Lite#7handles image steers by:.codexattachment cache before invoking Codex;codex exec resume --imageargument;The merged PR was exercised by 113 server tests and 69 web tests plus lint/build/repository checks, and all attachment review threads were resolved, including durable pass-through, private permissions, refresh persistence, repeated same-text steer disambiguation, and base64/localStorage handling.
For Codex Desktop, the equivalent data model should make one attachment record authoritative rather than persisting two representations with different lifetimes:
Suggested recovery/render order:
input_imagedata;attachment_missingcard with repair/export action — never an infinite spinner.During send, copy or materialize the clipboard image atomically before committing the UI-facing event. For existing affected rollouts, a migration/recovery pass can rebuild missing durable attachments from the embedded
response_item.input_imagedata and rewrite the event reference. This is a submitted implementation reference, not a claim that the upstream app already uses the same storage path.Independent reproduction on a different Windows 11 machine, plus a few details that I think narrow the fix down.
Still reproduces at HEAD, and it is the steady state rather than an edge case
26.818.5345.0, Windows 11 26200.cli_version 0.147.0-alpha.6.6,originator: "Codex Desktop"— the event still recordslocal_images: ["C:\Users\<user>\AppData\Local\Temp\codex-clipboard-<uuid>.png"]withimages: [].~/.codex/sessions+archived_sessions, spanning 2026-06-10 → 2026-08-12):| | |
|---|---|
| sessions containing images | 32 |
|
local_imagesrefs total | 50 || refs under
%TEMP%| 50 / 50 || refs still resolvable on disk | 0 / 50 |
|
input_imagebase64 copies in the same rollouts | 196 || affected sessions recoverable from base64 | 18 / 18 (100%) |
So every pasted image older than the temp-cleanup window is broken, not just the ones in one long thread. On Windows 11 this is default-on behavior, not something the user did: Storage Sense ships enabled with "delete temporary files that my apps aren't using" (
HKCU\...\StorageSense\Parameters\StoragePolicy,01=1,04=1), so%TEMP%is swept automatically.Root cause is one function, and it is unchanged on
mainThreadHistoryBuilder::build_user_inputsmaps the persisted event straight through with no existence check and no fallback:https://github.com/openai/codex/blob/fb0781b9eee6d2da741b984bed9dde95834d909d/codex-rs/app-server-protocol/src/protocol/thread_history.rs#L1502-L1507
Verified present at
main@fb0781b(2026-08-24, afterrust-v0.149.1). The model-facing path does degrade gracefully —Prompt::from_user_inputfalls back tolocal_media_error_placeholderwhenstd::fs::readfails (codex-rs/protocol/src/models.rs) — but the UI-facing path has no equivalent, which is why the result is an infinite spinner instead of an error card.Also worth noting: nothing under
codex-rs/ever copies an image intoCODEX_HOME. The TUI writes clipboard images to the system temp dir viatempfile()(codex-rs/tui/src/clipboard_paste.rs, prefixcodex-clipboard-), and the desktop frontend writes a UUID-named file to the same place. The durable copy is a design gap on the write side, not a cleanup race.The durable attachment store already exists — it is just text-only
~/.codex/attachments/is already used today, but only for pasted text:Pasted images could reuse exactly this directory and lifecycle instead of
%TEMP%, which makes the "copy to durable app storage" option in the original report considerably cheaper than it looks — no new storage mechanism, retention policy, or migration surface is needed.There is already a precedent for the render-side half, in the same function
#34385 ("Preserve audio across history and tool outputs",
6f78563, 2026-07-20) added exactly this kind of preservation for audio inthread_history.rs, including local audio in legacy user-message events. Images never got the same treatment. MakingLocalImagefall back to the already-persistedresponse_iteminput_imagedata URL when the path is gone would bring images to parity and would fix existing rollouts, not just new ones.Existing data is fully recoverable
Because the base64 copy is always present in the
response_item, a migration pass can rebuild every missing attachment with no data loss — 196/196 images in my store, covering 18/18 affected sessions. I extracted them all with a ~40-line script that walks the rollouts and decodespayload.content[].image_url; happy to attach it if useful.Possibly relevant to triage
#31590 ("Codex app stores pasted image file paths instead of copying bytes") was closed as completed on 2026-08-09, but the 2026-08-12 messages above still recorded a
%TEMP%path inlocal_images. Whatever landed there does not appear to cover the desktop paste path or the history-rendering half tracked here.