WordPress / WordPress/php-ai-client
Guzzle request options cause HTTP error responses to bypass ResponseUtil
@superdav42 is already working on this.
Since Jul 28, 2026.
- Dominant language
- PHP
- Stars
- 308
- Forks
- 84
- Avg merge
- 7d 21h
- Merged PRs (30d)
- 2
Description
Summary
When HttpTransporter has non-null RequestOptions and discovers a Guzzle-shaped client, it calls Guzzle's send() method with translated options. The options currently omit http_errors => false, so Guzzle can throw for 4xx/5xx responses before the response reaches ResponseUtil::throwIfNotSuccessful().
This leaves callers with the generic wrapper message HTTP client error occurred while sending request ... instead of the SDK's typed ClientException or ServerException.
Evidence
src/Providers/Http/HttpTransporter.php:send()selectssendWithGuzzle()whenever merged request options are present and the client matches Guzzle'ssend(RequestInterface, array)shape.src/Providers/Http/HttpTransporter.php:buildGuzzleOptions()translates timeout and redirect options but does not disable Guzzle's HTTP-status exceptions.ResponseUtilcan only translate the response afterHttpTransporter::send()returns it.- WordPress/php-ai-client#209 added the
529 => Overloadedmessage, but it only applies when the 529 response reachesResponseUtil. - The original observed failure is tracked downstream at https://github.com/WordPress/ai-provider-for-anthropic/issues/3.
The request-options path originated in #99 and PR #109. This report is specifically about preserving PSR-18-style response semantics on that Guzzle-specific options path.
Expected behavior
Guzzle-backed requests with RequestOptions should return HTTP error responses to the SDK. Provider code can then pass those responses to ResponseUtil, which throws the appropriate typed SDK exception. Network and transport failures should continue to use the existing exception path.
Proposed implementation
Files to modify
src/Providers/Http/HttpTransporter.php— passhttp_errors => falsein the Guzzle options produced bybuildGuzzleOptions().tests/unit/Providers/Http/HttpTransporterTest.php— add regression coverage for the option and an HTTP error response.tests/mocks/GuzzleLikeClient.php— only if needed to model Guzzle's status-error behavior in the focused test.
Complete write surface
- Callers/readers:
HttpTransporter::send(),sendWithGuzzle(), and providers that subsequently callResponseUtil::throwIfNotSuccessful(). - Mutation path:
HttpTransporter::buildGuzzleOptions()is the single Guzzle option translation path. - Tests/fixtures:
HttpTransporterTestandGuzzleLikeClient;ResponseUtilTestalready covers typed status translation independently. - Schemas/config/generated artifacts: none found; this changes an internal Guzzle option only.
Compatibility and hazards
- Apply
http_errorsonly to the Guzzle-shapedsend()path;ClientWithOptionsInterfaceand ordinary PSR-18sendRequest()paths should remain unchanged. - Disabling Guzzle status exceptions aligns this path with PSR-18 semantics, where 4xx/5xx responses are returned rather than treated as transport failures.
- Do not add automatic retry behavior in this change.
- Preserve timeout, connect-timeout, redirect, and network-exception behavior.
Acceptance criteria
- A Guzzle-shaped client called with non-null
RequestOptionsreceiveshttp_errors => false. - A simulated 529 response is returned by
HttpTransporterand can be translated byResponseUtilintoServerExceptionwith code529and theOverloadedmessage. - A representative 4xx response no longer takes the generic
HTTP client error occurredpath. - Existing timeout, redirect, successful-response, and network-exception tests continue to pass.
Verification
vendor/bin/phpunit tests/unit/Providers/Http/HttpTransporterTest.php
vendor/bin/phpunit tests/unit/Providers/Http/Util/ResponseUtilTest.php
composer lint
AI disclosure
This issue was investigated and drafted interactive OpenCode session.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.