fix(hypercore): log WebSocket close frames instead of warning "binary msg" - #74
Merged
Merged
Conversation
kiarash666
suggested changes
Jul 10, 2026
ifdario
requested changes
Jul 10, 2026
… msg"
`Stream::poll_next` decoded only `OpCode::Text` and routed every other frame into
`log::warn!("Hyperliquid sent a binary msg? {data:?}")`. Hyperliquid rotates
long-lived connections, closing them with a normal `1000` close frame and the
reason "Expired", so a perfectly healthy connection emits a spurious warning on
every rotation — about 9 times a day on a collector I run:
WARN hypersdk::hypercore::ws: Hyperliquid sent a binary msg? b"\x03\xe8Expired"
Match on the opcode instead:
- `Close` logs the status code and reason at INFO, via yawc's `Frame::close_code`
and `Frame::close_reason`
- `Ping` / `Pong` / `Continuation` are traced
- `Binary` keeps the original warning, which now means what it says
- `Text` is untouched, including its `unable to parse` warning
Control flow is unchanged: every arm falls through to the next loop iteration
exactly as the previous `else` did, the stream still ends when the peer closes,
and the caller's reconnect loop still fires. Only log levels and message text
change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
xxivq
force-pushed
the
fix/ws-close-frame-logging
branch
from
July 10, 2026 16:43
747f80b to
2a9a7a5
Compare
ifdario
approved these changes
Jul 10, 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.
Stream::poll_nextdecodes onlyOpCode::Textand routes every other frame intolog::warn!("Hyperliquid sent a binary msg? {data:?}").Hyperliquid rotates long-lived websocket connections, closing them with a normal
1000close frame and the reason"Expired". So a perfectly healthy connectionemits a spurious warning on every rotation — about 9 times a day on a collector I
run, which is otherwise clean:
\x03\xe8is 1000. It isn't a binary message; it's a close frame, and the SDKalready depends on
yawc, which exposesclose::CloseCode.What this changes
Matches on the opcode instead of testing for
Text:Closedecodes the RFC 6455 §5.5.1 status code and reason, logging at INFO.Ping/Pong/Continuationare traced. (yawc'sassemble_incomingreassembles fragments and yields them under their original opcode, so a raw
Continuationnever reaches here — that arm is defensive only.)Binarykeeps the original warning, which now means what it says.Textis untouched, including itsunable to parsewarning.What this does not change
Control flow is identical. Every arm falls through to the next loop iteration
exactly as the previous
elsedid; only theTextarm returnsPoll::Ready(Some(_)). The stream still ends when the peer closes, so thereconnect loop in
run_wsstill fires. Only log levels and message text differ.Tests
Adds a
#[cfg(test)] mod testsfordecode_close, including the exact payloadHyperliquid sends on rotation (
b"\x03\xe8Expired"→CloseCode::Normal,"Expired"), a close frame with no reason, and payloads too short to carry astatus code.
cargo test --libpasses (139 tests).cargo clippyadds no new warnings —examples/hypercore/priority-fee-bid.rsalready fails to build onmain,unrelated to this change.
cargo fmtclean.🤖 Generated with Claude Code