Codex Desktop: image thumbnails fail with "File stream access denied" — estuary download URL is fetched without Authorization
Summary
Image attachments in Codex Desktop (Windows) render as red "Failed" tiles. The renderer log shows:
warning [electron-message-handler] Image asset download failed
assetPointer=sediment://file_...
errorMessage="{\"detail\":\"File stream access denied.\"}"
pointerScheme=sediment resolverKind=codex
Root cause: the desktop fetches the estuary download URL without any credentials, and /backend-api/estuary/content requires auth. Verified by replaying the exact requests:
| Request | Result |
|---|---|
| GET /backend-api/files/download/{file_id} (with Bearer token) | 200 → returns signed download_url |
| GET https://chatgpt.com/backend-api/estuary/content?id=...&sig=... anonymous | 403 {"detail":"File stream access denied."} |
| Same estuary URL with Bearer + ChatGPT-Account-Id | 200, valid image bytes |
The signed sig query param is not sufficient on its own — the endpoint still demands the Bearer token.
Why the app sends no credentials
In the packaged main bundle (build 26.715.72359):
performDesktopFetchattaches auth only when the request carries theX-OpenAI-Attach-Authmarker header, or whenshouldInferCodexApiAuth(url)returns true.shouldInferCodexApiAuthwhitelists only/wham,/api/wham,/backend-api/wham— estuary paths are missing.- The image resolver (
prompt-editorchunk) fetches thedownload_urlwithrequestHeaders = null, so only the infer path could ever attach auth — and it doesn't cover estuary.
The upload path does special-case estuary URLs (unwrapping combined upload URLs); the download path was missed, presumably during the estuary storage migration.
Suggested fix (verified locally)
Add estuary to the infer list:
|| n === `/backend-api/estuary` || n.startsWith(`/backend-api/estuary/`)
in shouldInferCodexApiAuth. I applied this one-line change to a local copy of the packaged app.asar and all previously failing thumbnails (4 sediment://file_... assets across multiple conversations) now download and render correctly.
Environment
- Codex Desktop app version 26.715.72359 (MSIX package 26.715.10079.0)
- Windows 11, ChatGPT Pro account
- Repro: send any image in the composer, then reopen the conversation (or focus it after the local copy is gone) — the thumbnail request goes through the estuary resolver and fails.
Possibly related
- #29880 (macOS, thumbnails as gray placeholders) — likely the same estuary auth gap
- #32677 / #33034 (plugin icons/thumbnails broken) — same asset-download code path