close the media 403 investigation: the bytes are gone
The render check settled it. Scrolling the whole conversation found sets of
images that do NOT display in ChatGPT — a set of 6 and a set of 4 — and they
are exactly our failures: the 6 are the records that 404 outright, the 4 are
the refused attachment batch we dumped (image.png, image(1).png,
image(2).png + 1). Every set that displays downloaded fine.
So the 403 was never OpenAI withholding something. It is the same failure
their own UI hits. All 19 are unrecoverable.
What the investigation established, now recorded in media.py and the
changelog so it is not repeated:
- uploads do not expire (36/36 sampled, 2025-09 → 2026-08, still live), so
export cadence was never the variable
- 7 records 404; 12 report state=ready with a library_file_id
- /files/{id}/download mints the signed estuary/content URL the UI fetches,
and refuses the survivors regardless of headers, Authorization, gizmo_id,
conversation_id, Referer or namespace; the Library id is file_not_found
- all survivors were created 2026-07-14 within minutes of each other yet
appear in conversations predating that date — a Library migration that
kept the metadata and lost the bytes
Dropping the nine one-off probes; their findings live in the code comments
and changelog, and git history has the scripts if they are ever wanted.
This commit is contained in:
+13
-2
@@ -160,8 +160,19 @@ def _classify_failure(error: ProviderError) -> str:
|
||||
Note that a bare 403 from ChatGPT usually means *gone*, not *refused*:
|
||||
its download endpoint reports a deleted upload as 403 Forbidden. The
|
||||
provider confirms that against /files/{id} before raising, so a failure
|
||||
that reaches here still saying "forbidden" is one where the asset really
|
||||
does still exist — worth looking at, unlike an expired upload.
|
||||
that reaches here still saying "forbidden" is one where the file record
|
||||
survives.
|
||||
|
||||
``forbidden`` does NOT mean recoverable. Investigated exhaustively
|
||||
2026-08-17 (19 assets): those records report ``state: "ready"`` and carry
|
||||
a ``library_file_id``, yet /files/{id}/download — the endpoint that mints
|
||||
the signed estuary/content URL the web UI itself fetches — refuses them,
|
||||
and the Library id is rejected as ``file_not_found``. Decisively, the same
|
||||
images render blank in ChatGPT's own UI. Nothing was withheld from us; the
|
||||
bytes are gone and only the metadata survived, apparently from a Library
|
||||
migration dated 2026-07-14. Do not spend another afternoon on it: no
|
||||
header, scope, namespace or id form reaches these. The bucket stays
|
||||
separate only because the two failures look different on the wire.
|
||||
"""
|
||||
detail = str(error.original).lower()
|
||||
if "404" in detail or "not found" in detail or "no longer exists" in detail:
|
||||
|
||||
Reference in New Issue
Block a user