[Bug]: UnserializableResponse when Files::retrieve() returns HTML 503
Description
When calling Files::retrieve($fileId) via the PHP SDK, intermittent 503 responses from the API edge (HTML “503 Service Temporarily Unavailable” from OpenAI's nginx) cause the transporter to attempt json_decode() on the HTML body. This triggers:
OpenAI\Exceptions\UnserializableResponse
Syntax error
vendor/openai-php/client/src/Transporters/HttpTransporter.php:62
Because the response isn’t JSON, the SDK error is misleading and hides the actual HTTP status/body. This makes handling/retrying 5xx conditions difficult.
Steps To Reproduce
-
Environment (example):
- PHP: 8.x
- SDK:
openai-php/client(latest at time of issue)
-
Code (minimal):
$fileId = 'file_XXXXXXXXXXXX'; // Repro: call retrieve on an existing file id $file = $client->files()->retrieve($fileId); -
Intermittently, the API responds with a 503 HTML page (edge/nginx). If you dump the raw contents in the transporter you’ll see something like:
<html> <head><title>503 Service Temporarily Unavailable</title></head> <body> <center><h1>503 Service Temporarily Unavailable</h1></center> <hr><center>nginx</center> </body> </html> -
The SDK attempts to
json_decode()this HTML and throws:OpenAI\Exceptions\UnserializableResponse (Syntax error) at vendor/openai-php/client/src/Transporters/HttpTransporter.php:62
OpenAI PHP Client Version
v0.16.0
PHP Version
8.4.6
Notes
-
The error originates here:
vendor/openai-php/client/src/Transporters/HttpTransporter.php:62- The transporter always tries to decode the body as JSON before considering that it might be an HTML error page.
Thanks for report. I was under impression this was fully fixed. I'll take your sample and dig into what went wrong.
O wait - an UnserializableResponse is what I expect. Its not JSON - that's the expectation. It used to crash much uglier with a type issue, this time its an exception.
The gap is we have is endpoints that don't return JSON (audio, file contents, etc) - those have it much more difficult. Since we are under assumption that JSON is what is being returned we go under that expectation.
So I believe next step here is one of following:
- Make it more clear the UnserializableResponse is the one to use, extend with statusCode so you don't have to parse the Response object on it to identify HTTP code.
- Introduce a new top-level error class (or shove this into ErrorException). Maybe anything 5xx automatically falls into it. Since we have handling for some 4xx already.
- Do nothing - this has answered your query.