Skip to content

fix(hypercore): log WebSocket close frames instead of warning "binary msg" - #74

Merged
ifdario merged 1 commit into
infinitefield:mainfrom
xxivq:fix/ws-close-frame-logging
Jul 10, 2026
Merged

fix(hypercore): log WebSocket close frames instead of warning "binary msg"#74
ifdario merged 1 commit into
infinitefield:mainfrom
xxivq:fix/ws-close-frame-logging

Conversation

@xxivq

@xxivq xxivq commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Stream::poll_next decodes only OpCode::Text and routes every other frame into
log::warn!("Hyperliquid sent a binary msg? {data:?}").

Hyperliquid rotates long-lived websocket 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, which is otherwise clean:

WARN hypersdk::hypercore::ws: Hyperliquid sent a binary msg? b"\x03\xe8Expired"
INFO hypersdk::hypercore::ws: Disconnected from wss://api.hyperliquid.xyz/ws, attempting to reconnect...

\x03\xe8 is 1000. It isn't a binary message; it's a close frame, and the SDK
already depends on yawc, which exposes close::CloseCode.

What this changes

Matches on the opcode instead of testing for Text:

  • Close decodes the RFC 6455 §5.5.1 status code and reason, logging at INFO.
  • Ping / Pong / Continuation are traced. (yawc's assemble_incoming
    reassembles fragments and yields them under their original opcode, so a raw
    Continuation never reaches here — that arm is defensive only.)
  • Binary keeps the original warning, which now means what it says.
  • Text is untouched, including its unable to parse warning.

What this does not change

Control flow is identical. Every arm falls through to the next loop iteration
exactly as the previous else did; only the Text arm returns
Poll::Ready(Some(_)). The stream still ends when the peer closes, so the
reconnect loop in run_ws still fires. Only log levels and message text differ.

Tests

Adds a #[cfg(test)] mod tests for decode_close, including the exact payload
Hyperliquid sends on rotation (b"\x03\xe8Expired"CloseCode::Normal,
"Expired"), a close frame with no reason, and payloads too short to carry a
status code.

cargo test --lib passes (139 tests). cargo clippy adds no new warnings —
examples/hypercore/priority-fee-bid.rs already fails to build on main,
unrelated to this change. cargo fmt clean.

🤖 Generated with Claude Code

@kiarash666 kiarash666 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.

Comment thread src/hypercore/ws.rs Outdated
… 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
xxivq force-pushed the fix/ws-close-frame-logging branch from 747f80b to 2a9a7a5 Compare July 10, 2026 16:43
@ifdario
ifdario merged commit c8cc74b into infinitefield:main Jul 10, 2026
@xxivq
xxivq deleted the fix/ws-close-frame-logging branch July 10, 2026 20:37
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