Why a WebSocket subscription goes silent
Last updated:
At a glance
| Property | Value |
|---|---|
| Subscription lifetime (Geth) | Coupled to one WebSocket connection; removed when it closes |
| After a reconnect | Resubscribe and use the new subscription ID |
| Missed events | No documented replay; backfill with regular RPC calls |
| Abnormal close | Code 1006 (RFC 6455): closed without a Close frame being received |
| newHeads during a reorg | Can emit several headers at the same height |
What you see
A long-running listener stops printing new blocks or logs. The process is alive, the socket reconnected, and there is no error — just silence. Or events resume after a reconnect but some blocks in between are missing, and newHeads occasionally delivers two different blocks at the same height.
Why this happens
Geth's documentation is explicit: subscriptions are coupled to a connection, and if the connection is closed, all subscriptions created over it are removed. A new connection therefore starts with none, and the subscription ID the server returned on the old connection identifies nothing on the new one. Solana's pub/sub also returns a subscription ID per subscribe request and pushes notifications to it; its documentation does not describe subscriptions surviving a reconnect, so resubscribing is the safe assumption there too. Connections close for ordinary reasons: a server restart or deploy, an idle timeout on a proxy, a network change on the client. When the connection is lost without a Close frame being received, RFC 6455 defines the close code the client sees as 1006 — a reserved value meaning the connection closed abnormally. Subscriptions deliver events from the moment they exist; neither API documents a replay of what was emitted while you were disconnected. Separately, during a chain reorganisation an EVM newHeads subscription emits the last header of the new chain, so it can deliver several headers at the same height, and a node catching up after being out of sync may emit only the last of several blocks.
What to do
- On every reconnect, create all subscriptions again and replace the stored subscription IDs.
- Remember the last block number or slot you processed; after resubscribing, backfill the gap with regular calls (eth_getLogs or eth_getBlockByNumber on EVM chains, getSignaturesForAddress or getBlock on Solana).
- Make handlers idempotent and key events by block hash and log index (or signature), so replays from the backfill and duplicates after a reorg are harmless.
- Send periodic ping frames (or a cheap request) to detect a dead connection early, and reconnect with backoff.
- Treat newHeads as "the chain head changed", not as a strictly increasing sequence: handle repeated heights and gaps.
When this is not our problem
Connection-scoped subscriptions and the lack of a documented replay come from the JSON-RPC pub/sub model itself, whoever operates the node, Triport included. Any long-lived WebSocket can be closed by either side, so resubscribe-and-backfill logic is needed with every provider.
FAQ
- Do RPC subscriptions survive a WebSocket reconnect?
- No. Geth documents that subscriptions are removed when their connection closes, and Solana's pub/sub documents no way to carry them over. After reconnecting, call eth_subscribe (or the Solana *Subscribe method) again and use the new subscription ID.
- How do I get events I missed while disconnected?
- Record the last block or slot you processed and backfill from there with regular RPC calls such as eth_getLogs, then continue with the new subscription.