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
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 — pass http_errors => false in the Guzzle options produced by buildGuzzleOptions().
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 call ResponseUtil::throwIfNotSuccessful().
- Mutation path:
HttpTransporter::buildGuzzleOptions() is the single Guzzle option translation path.
- Tests/fixtures:
HttpTransporterTest and GuzzleLikeClient; ResponseUtilTest already covers typed status translation independently.
- Schemas/config/generated artifacts: none found; this changes an internal Guzzle option only.
Compatibility and hazards
- Apply
http_errors only to the Guzzle-shaped send() path; ClientWithOptionsInterface and ordinary PSR-18 sendRequest() 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
RequestOptions receives http_errors => false.
- A simulated 529 response is returned by
HttpTransporter and can be translated by ResponseUtil into ServerException with code 529 and the Overloaded message.
- A representative 4xx response no longer takes the generic
HTTP client error occurred path.
- 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.
Summary
When
HttpTransporterhas non-nullRequestOptionsand discovers a Guzzle-shaped client, it calls Guzzle'ssend()method with translated options. The options currently omithttp_errors => false, so Guzzle can throw for 4xx/5xx responses before the response reachesResponseUtil::throwIfNotSuccessful().This leaves callers with the generic wrapper message
HTTP client error occurred while sending request ...instead of the SDK's typedClientExceptionorServerException.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.529 => Overloadedmessage, but it only applies when the 529 response reachesResponseUtil.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
RequestOptionsshould return HTTP error responses to the SDK. Provider code can then pass those responses toResponseUtil, 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
HttpTransporter::send(),sendWithGuzzle(), and providers that subsequently callResponseUtil::throwIfNotSuccessful().HttpTransporter::buildGuzzleOptions()is the single Guzzle option translation path.HttpTransporterTestandGuzzleLikeClient;ResponseUtilTestalready covers typed status translation independently.Compatibility and hazards
http_errorsonly to the Guzzle-shapedsend()path;ClientWithOptionsInterfaceand ordinary PSR-18sendRequest()paths should remain unchanged.Acceptance criteria
RequestOptionsreceiveshttp_errors => false.HttpTransporterand can be translated byResponseUtilintoServerExceptionwith code529and theOverloadedmessage.HTTP client error occurredpath.Verification
AI disclosure
This issue was investigated and drafted interactive OpenCode session.