Conversation
Both providers explain their errors. Typesafe's 422 details the offending
field; OpenRouter answers with {"error": {"code", "message"}}. Neither
reached the exception. ApiError#message was a constant -- "unprocessable
entity" -- and the explanation sat on #body as a JSON string, so every
caller who wanted the reason wrote the same parse, and every log line
that printed the exception and not the body threw the reason away.
ApiError now parses a JSON object body into #detail, #error_code, and
#parsed_body, reading them whether the payload nests them under "error"
or puts them at the top level, and appends the detail to the message. A
422 reads "unprocessable entity: questions.sev.criteria must have at
least 2 entries".
Everything that is not a JSON object -- an HTML error page from a proxy,
plain text from a load balancer, an empty body, a JSON array -- leaves
all three nil and the message exactly as it was. Parsing happens once,
lazily, and #body is still the raw string it always was.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Both providers explain their errors. Typesafe's 422 details the offending field; OpenRouter answers with
{"error": {"code", "message"}}. Neither reached the exception.ApiError#messagewas a constant —"unprocessable entity"— and the explanation sat on#bodyas a JSON string, so every caller who wanted the reason wrote the same parse, and every log line that printed the exception and not the body threw the reason away.ApiErrornow parses a JSON object body into#detail,#error_codeand#parsed_body, reading them whether the payload nests them under"error"or puts them at the top level, and appends the detail to the message:Everything that isn't a JSON object — an HTML error page from a proxy, plain text from a load balancer, an empty body, a JSON array — leaves all three
niland the message exactly as it was. Parsing happens once, lazily, and#bodyis still the raw string.Tests
test/error_body_test.rb, 13 cases, most of them about bodies that aren't well-formed error objects.Draft: part of a security and API-coverage audit, opened for reference rather than as a request for immediate review. Independent of the other branches, each off
main. Suite green on Ruby 3.2.11, 3.3.8 and 3.4.8.🤖 Generated with Claude Code