Repository navigation
fix(client): retain API status when error body reads fail - #73
rudycelekli wants to merge 1 commit into
Conversation
Signed-off-by: Rudy Celekli <rudy@gradiahq.com>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs maintainer review before merge. Reviewed October 6, 2026, 3:28 AM ET / 07:28 UTC. ClawSweeper reviewWhat this changesThe client preserves HTTP error status and the underlying read failure when an error response body is interrupted, with public-client regression coverage and an Unreleased changelog entry. Merge readiness✅ Ready for maintainer review This PR fixes a documented error-handling gap that remains on current main and in v0.4.11. The supplied real HTTP before/after observations support the repair, and no actionable patch defect was found. Priority: P2 Review scores
Verification
How this fits togethergoplaces routes public library and CLI requests through a shared HTTP client for Google Places and Routes. That client turns upstream responses into result payloads or errors that callers can inspect. flowchart TD
A[Library or CLI request] --> B[Shared HTTP client]
B --> C[Upstream HTTP response]
C --> D[Read bounded response body]
D --> E{Body read fails}
E -->|Non-success status| F[HTTP status and read cause]
E -->|Success status| G[Read cause only]
E -->|No| H[Normal status handling]
Before mergeNone. Agent review detailsSecurityNone. Review metrics
Technical reviewBest possible solution: Keep interrupted non-2xx responses inspectable by both HTTP status and read cause without exposing partial bodies or altering successful-response handling. Do we have a high-confidence way to reproduce the issue? Yes: a short HTTP body with a larger declared Content-Length reaches main's early read-error return and loses APIError status. Source inspection and the contributor's real HTTP before/after output support this path; the reviewer did not execute it. Is this the best way to solve the issue? Yes: standard multiple error wrapping preserves the documented status and cause without changing the public error struct or duplicating request handling. AGENTS.md: not found in the target repository. Codex review notes: model internal, reasoning medium; reviewed against 9883e1044f50. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
|
Summary
The client reference promises non-2xx statuses as APIError. A truncated HTTP error body instead returned only a read error, discarding its actionable status. Preserve errors.As(APIError) and errors.Is(read cause) through standard multiple wrapping without changing the public APIError struct layout.
Reference: upstream contract.
Reproduction and producer proof
Actual HTTP server sends 429, 503 or 401 with Content-Length 100 and a shorter body. Before: 'goplaces: read response: unexpected EOF', errors.As(*APIError) false. After: 'goplaces: api error (429): goplaces: read response: unexpected EOF' (analogous 503/401), errors.As returns the exact status and errors.Is(io.ErrUnexpectedEOF) stays true. Truncated 200 remains a read failure without an invented APIError. Partial fixture-key contents are not exposed.
Owned local HTTP fixtures only; no live Google calls, credentials, quota usage or billing verification are claimed.
Verification
Verified signed head: 87a2f5f (DCO sign-off). Repository coverage 92.1%. Hosted checks are separate from these local results.
Assistance
Prepared with AI assistance; the reproduced behavior, source review and checks were completed before submission.
Captured native output
Actual producer observations from the owned loopback fixture (the API key is a dummy value):
{ "before": [ { "api_error": false, "api_status": 0, "error": "goplaces: read response: unexpected EOF", "http_status": 429, "unexpected_eof": true }, { "api_error": false, "api_status": 0, "error": "goplaces: read response: unexpected EOF", "http_status": 503, "unexpected_eof": true }, { "api_error": false, "api_status": 0, "error": "goplaces: read response: unexpected EOF", "http_status": 401, "unexpected_eof": true }, { "api_error": false, "api_status": 0, "error": "goplaces: read response: unexpected EOF", "http_status": 200, "unexpected_eof": true } ], "after": [ { "api_error": true, "api_status": 429, "error": "goplaces: api error (429): goplaces: read response: unexpected EOF", "http_status": 429, "unexpected_eof": true }, { "api_error": true, "api_status": 503, "error": "goplaces: api error (503): goplaces: read response: unexpected EOF", "http_status": 503, "unexpected_eof": true }, { "api_error": true, "api_status": 401, "error": "goplaces: api error (401): goplaces: read response: unexpected EOF", "http_status": 401, "unexpected_eof": true }, { "api_error": false, "api_status": 0, "error": "goplaces: read response: unexpected EOF", "http_status": 200, "unexpected_eof": true } ] }