TLDR:Documentation Index
Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
Use this file to discover all available pages before exploring further.
- WebSocket close code
1009(MESSAGE_TOO_BIG) fires when the inbound frame exceeds the client’s payload cap — common on SolanablockSubscribebecause mainnet blocks can be tens of MiB. - Python
websocketsdefaults to a 1 MiB cap (max_size=2**20). Raise or disable it on theconnect()call. - Node
wsdefaults to a 100 MiB cap (maxPayload). Usually fine, but disable it (Infinity) for full blocks. - Raising the cap stops
1009, butblockSubscribeitself is unstable upstream. For production, use Yellowstone gRPC Geyser.
What close code 1009 means
Per RFC 6455 §7.4.1, close code1009 (MESSAGE_TOO_BIG) signals that an endpoint received a frame or message larger than it is willing or able to process. It is a defensive cap meant to protect the client from resource exhaustion or a hostile server flooding it with oversized frames.
On Solana, blockSubscribe pushes the full block payload — transactions, inner instructions, log messages, balance deltas. On Mainnet this is routinely well above 1 MiB and can climb past 10 MiB during heavy activity. A library default of 1 MiB will drop the connection on the first large block.
The symptom differs by library:
- Python
websocketsraisesPayloadTooBig, then closes with code1009. - Node
wsemits acloseevent withcode === 1009.
1006 (“abnormal closure”) often shows up on the same workload after the 1009 fix — that one is the upstream instability, not a payload-size issue. Raising the client cap will not fix 1006; switching to Geyser will.
Python: websockets default limit
The websockets library sets max_size = 2**20 bytes (1 MiB) per message and max_queue = 32 buffered messages. Any inbound frame larger than max_size triggers:
Fix
Passmax_size to connect() — raise it, or set None to disable the cap:
max_size=None— disable the cap entirely.max_size=10 * 1024 * 1024— 10 MiB ceiling, a reasonable headroom forblockSubscribe.
max_queue at its default unless you have a slow consumer; raising it just hides backpressure.
Node.js: ws default limit
The ws library defaults to maxPayload = 100 * 1024 * 1024 (100 MiB), which usually covers Solana blocks. If you ever see code 1009, raise the cap or disable it:
maxPayload: 0orInfinity— no cap.maxPayload: <bytes>— custom cap. Set it to your worst-case block size with headroom.
Trimming the payload instead
If you can live with less detail, narrow whatblockSubscribe returns. This also makes the stream noticeably more stable — our internal load testing showed transactionDetails: "signatures" survives 1,000+ concurrent clients while "full" started disconnecting after ~40 seconds at a single client.
transactionDetails: "signatures"— drop full transaction bodies, keep signatures only. Most reliable option if you don’t need the full body.transactionDetails: "none"— block metadata only, no transactions.showRewards: false— skip the rewards array.- Filter to a single program via
{"mentionsAccountOrProgram": "<pubkey>"}inparams[0]— only blocks containing that program’s transactions are pushed.
blockSubscribe reference for the full parameter list.
Production path: Yellowstone gRPC Geyser
Even after raising the client cap,blockSubscribe itself is upstream-flagged as unstable on busy programs. Our load tests show connections drop within ~40 seconds even at 1 concurrent client when transactionDetails: "full" is used. Symptoms include 1006 (abnormal closure) closes and silently dropped notifications — not just the 1009 case the fixes above address.
The recommended production path is Yellowstone gRPC Geyser — a Chainstack add-on that delivers the same data (blocks, transactions, account updates, slots) over a gRPC stream, with no RFC-6455 payload caps and without the upstream blockSubscribe instability. Existing blockSubscribe consumers migrate to a gRPC subscribe call against the Geyser endpoint.
See:
- Yellowstone gRPC Geyser plugin
- Solana: listening to programs using Geyser and Yellowstone gRPC (Node.js)
- Solana: listening to pump.fun token mint using Geyser
Billing note
EachblockSubscribe push counts as 1 request unit. On Mainnet that is one RU per slot — roughly two per second when the network is healthy. Factor the subscription cost into your plan before pointing a long-running consumer at blockSubscribe.