Skip to content

Surface validation errors reported as a list - #46

Merged
dangra merged 2 commits into
mainfrom
sprites-api-error-list
Sep 9, 2026
Merged

dangra merged 2 commits into
mainfrom
sprites-api-error-list

Conversation

@dangra

@dangra dangra commented Sep 8, 2026 •

Copy link
Copy Markdown
Member

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. APIError only understood the singular shape:

ErrorCode string `json:"error"`
Message   string `json:"message"`

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:

API error (status 400)

and no way to find out why short of capturing the raw body by hand. That is how this was found.

The change

APIError gains Errors []string, and Error() falls back to joining it with "; " before the bare-status fallback. Precedence is unchanged for everything that already worked:

  1. Message, when present
  2. ErrorCode, when present
  3. Errors, joined ← new
  4. API 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 vet and golangci-lint v2.11.3 are clean.

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.
Copilot AI lite review requested due to automatic review settings September 8, 2026 19:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.
@dangra
dangra merged commit 3ff87fc into main Sep 9, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants