Repository navigation
Surface validation errors reported as a list - #46
Merged
Merged
Conversation
Some endpoints report a failed request as a single message, and some report it as a list of them — a create rejected for several reasons at once returns one entry per reason. APIError only understood the singular shape, so for the list shape both Message and ErrorCode stayed empty and Error() fell through to its "API error (status 400)" fallback. The effect was that the server said exactly what was wrong and the SDK dropped it: callers got a bare status and no way to find out why, short of capturing the raw body themselves. APIError now carries Errors, and Error() falls back to joining it before the bare-status fallback. The singular shapes keep their existing precedence, so a body carrying both still reads as its message, and an empty list is still not a message.
The example body named a request parameter and its accepted values, which is incidental to what the test covers — the shape of an error, not the endpoint that produced it.
jeregrine
approved these changes
Sep 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Some endpoints report a failed request as a single message, and some report it as a list of them — a request rejected for several reasons at once returns one entry per reason.
APIErroronly understood the singular shape:A list body unmarshals cleanly into that (unknown fields are ignored), leaving both fields empty, so
Error()fell through to its bare-status fallback. The server said exactly what was wrong and the SDK dropped it, leaving callers with:and no way to find out why short of capturing the raw body by hand. That is how this was found.
The change
APIErrorgainsErrors []string, andError()falls back to joining it with"; "before the bare-status fallback. Precedence is unchanged for everything that already worked:Message, when presentErrorCode, when presentErrors, joined ← newAPI error (status N)So a body carrying both a message and a list still reads as its message, and the list stays available for a caller that wants every reason. The "nothing was parsed" fallback now also counts a populated list as parsed.
An empty
"errors": []is deliberately not treated as a message — it would otherwise produce an empty error string, which is worse than the status.Tests
Five cases: the single-entry list, several entries joined, message-wins-over-list, the singular shapes still working (including the rate-limit one), and both fallbacks.
go test,go vetandgolangci-lint v2.11.3are clean.