fix(transport): reject 200-OK { type: "error" } envelopes with HttpRequestError - #94
Merged
Conversation
…questError
Hyperliquid reports some failures inside a 200 OK response as a
top-level { type: "error", message } envelope (the explorer/rpc failure
shape). HttpTransport.request() validated only the HTTP status and
Content-Type, so such envelopes were returned to callers as data:
unvalidated info methods silently yielded the envelope as a "result",
and schema-validated methods failed with a confusing ValidationError
instead of the server's message. Upstream @nktkas/hyperliquid threw on
these envelopes; this fork had dropped the check.
request() now checks the parsed body after JSON.parse: a non-null,
non-array object with type === "error" throws HttpRequestError carrying
the server's message string when present (truncated body text
otherwise), a readable recreated Response, and the redacted request
snapshot. The invalid-JSON try block is narrowed to the parse alone so
the new throw is not rewrapped as "Invalid JSON response body".
Only top-level type === "error" envelopes throw: array bodies, normal
objects, nested type fields, and the exchange endpoint's
{ status: "err" } envelope (owned by the API layer) still resolve at
transport level. The explorer API layer's assertSuccessResponse remains
as a safety net for custom transports and is documented as such.
Docs: module diagram, class/method JSDoc, and error-handling.md updated
to enumerate the new failure case.
Fixes #91
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Merged
joeblau
added a commit
that referenced
this pull request
Aug 4, 2026
Four fixes, each cross-verified to agreement by three independent reviewers (Claude, Kimi K3 Max, Codex gpt-5.6-sol xhigh): - #89 subscription failures notify every subscriber + failureSignal (#93) - #90 WebSocket message pacing on by default, flush charging fixed (#96) - #91 200-OK { type: "error" } envelopes throw HttpRequestError (#94) - #92 wallet shape detection by member presence, not arity (#95) 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.
Summary
HttpTransport.request()now throwsHttpRequestErrorwhen a 200-OK body is Hyperliquid's top-level{ type: "error", message }failure envelope, carrying the server's own message (restores the check upstream@nktkas/hyperliquidhad)type: "error"fields, and exchange-style{ status: "err" }envelopes still resolveassertSuccessResponsedocumented as the safety net for custom transports; docs/error-handling.md updated; 6 new transport testsVerification (3-agent agreement)
bun run check+ 1965 offline tests, 0 failFixes #91
🤖 Generated with Claude Code