feat(errors): expose upstream provider errors as structured JSON - #489
Open
Destynova2 wants to merge 1 commit into
Open
feat(errors): expose upstream provider errors as structured JSON#489Destynova2 wants to merge 1 commit into
Destynova2 wants to merge 1 commit into
Conversation
On an upstream failure grob already forwards the verbatim HTTP status and the
provider's body (better than gateways that flatten a structured error into an
empty 500). But the body reached the client only as a `message` string, often
prefixed ("anthropic API error: {…}"), so a client could not read the provider's
own `error.type`/`code` without re-parsing a blob.
`into_response` now extracts the first embedded JSON object/array from the body
and attaches it as `error.upstream_error`, alongside the existing string
`message`, `provider` and `upstream_status`. Additive and backward compatible —
clients reading `message` are unaffected; agents that branch on the provider's
error type now can.
Tested: `extract_leading_json` (prefix / pure / trailing-junk / none) and a 429
ProviderUpstream response asserting status 429 + parseable `upstream_error`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Destynova2
enabled auto-merge (squash)
July 28, 2026 21:07
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.
Fidelity gap (from the competitive analysis)
The analysis flags "provider error detail lost" — Envoy turning a structured
provider error into an empty HTTP 500.
grob is already ahead: it forwards the verbatim upstream status and the
provider body (
error.rsProviderUpstream). But the body reached the clientonly as a
messagestring, often prefixed ("anthropic API error: {…}"), so aclient had to re-parse a blob to read the provider's own
error.type/code.Change
into_responsenow extracts the first embedded JSON object/array from the bodyand attaches it as
error.upstream_error, structured, alongside the existingmessage/provider/upstream_status:{ "error": { "type": "error", "message": "anthropic API error: {…}", "provider": "anthropic", "upstream_status": 429, "upstream_error": { "type": "error", "error": { "type": "rate_limit_error", "message": "slow down" } } } }Additive and backward compatible — clients reading
messageare unaffected;agents that branch on the provider's error type now can, without string-parsing.
Tests
extract_leading_json_handles_prefix_pure_and_none— prefixed body, pure JSON, trailing junk, and no-JSON.provider_upstream_forwards_status_and_structured_error— 429 forwarded verbatim + parseableupstream_error.cargo test --lib server::error— 42 passed.Part of the fidelity sweep (feeds #484).
🤖 Generated with Claude Code