Skip to content

fix(ws): use uint64 for params.Subscription in incoming notifications#427

Open
ozpool wants to merge 1 commit into
solana-foundation:mainfrom
ozpool:fix/ws-subscription-id-uint64-286
Open

fix(ws): use uint64 for params.Subscription in incoming notifications#427
ozpool wants to merge 1 commit into
solana-foundation:mainfrom
ozpool:fix/ws-subscription-id-uint64-286

Conversation

@ozpool
Copy link
Copy Markdown

@ozpool ozpool commented Apr 30, 2026

Closes #286.

Bug

The websocket pubsub response type in rpc/ws/types.go was defined as:

type params struct {
    Result       *stdjson.RawMessage `json:"result"`
    Subscription int                 `json:"subscription"`
}

The validator emits subscription ids as JSON unsigned 64-bit integers. With the field typed as int the decode in decodeResponseFromMessage fails on 32-bit builds for any id above math.MaxInt32, and on 64-bit builds for any id above math.MaxInt64. That is exactly the path users hit in #286: unable to decode client response from SlotSubscribe() (and the same shape for any other ws subscription). The bug was diagnosed in the issue thread by @AliakseiM, who pointed at this exact field.

Fix

Switch Subscription to uint64. The field is not consumed downstream — handleMessage parses the routing key separately via getUint64WithOk — but it has to be present so encoding/json does not error on the inbound notification. uint64 matches what the validator and handleMessage already use everywhere, and lines up with the recent #400 work that hardened request ids against the same JSON-safe-integer footgun.

Tests

TestResponseDecodesLargeSubscriptionID (new) decodes a notification with subscription == math.MaxUint64 to pin the new behavior.

$ go test -count=1 ./rpc/ws/... ./rpc/
ok   github.com/gagliardetto/solana-go/rpc/ws   0.325s
ok   github.com/gagliardetto/solana-go/rpc      0.680s

Diff size

 rpc/ws/types.go      | +9 -2
 rpc/ws/types_test.go | +22

The websocket pubsub response type was defined as

    type params struct {
        Result       *stdjson.RawMessage `json:"result"`
        Subscription int                 `json:"subscription"`
    }

but the validator emits subscription ids as JSON unsigned 64-bit
integers. With the field typed as int the decode in
decodeResponseFromMessage fails on 32-bit builds for any id above
math.MaxInt32, and on 64-bit builds for any id above math.MaxInt64
— the path users hit in practice when the validator hands out a
sufficiently large id (issue solana-foundation#286).

The Subscription field is not consumed downstream — handleMessage
parses the routing key separately via getUint64WithOk — but it has
to be present so encoding/json does not error on the inbound
notification. Switching the type to uint64 keeps that contract and
matches what the validator and handleMessage already use everywhere.

Adds a regression test that decodes a notification with subscription
== math.MaxUint64 to pin the new behavior.

Closes solana-foundation#286.
@ozpool
Copy link
Copy Markdown
Author

ozpool commented May 19, 2026

Hi @sonicfromnewyoke — also ~19 days open with no review. Small ws typing fix — params.Subscription in incoming notifications is parsed as uint64 to match the spec instead of being narrowed. Happy to rebase if needed. Thanks.

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.

"unable to decode client response" when using /rpc/ws Client's SlotSubscribe()

1 participant