Why Ethereum Block Subscriptions Are Unreliable

December 26, 2024

If you're building an Ethereum application that needs real-time block data, you've probably considered using websocket subscriptions. But before you dive in, there's something you should know about their reliability - or lack thereof.

I recently built a simple block indexer using Viem, a popular TypeScript library for Ethereum. The code looked straightforward enough:

import { createPublicClient, webSocket } from "viem"
import { mainnet } from "viem/chains"

const client = createPublicClient({
    chain: mainnet,
    transport: webSocket("wss://ethereum-rpc.publicnode.com"),
})

const unwatch = client.watchBlocks({
    emitMissed: true,
    emitOnBegin: true,
    onBlock: (block) => {
        const blockNumber = block.number
        const blockHashSimple = block.hash.slice(-10)
        const blockParentHashSimple = block.parentHash.slice(-10)
        console.log(
            `n=${blockNumber} h=${blockHashSimple} p=${blockParentHashSimple}`
        )
    },
    onError: (error) => console.log(error),
})

Simple and clean, right? Well, the output tells a different story.

When I ran this code, I started seeing some bizarre behavior. Take a look at this sequence:

n=21486372 h=793290bbf4 p=76d536993d
n=21486373 h=fbb51ac635 p=793290bbf4
n=21486373 h=fbb51ac635 p=793290bbf4
n=21486374 h=5e78d32503 p=fbb51ac635
n=21486375 h=8cfd886a8d p=5e78d32503
n=21486377 h=502ff4bc4b p=3ae8ff4e38
n=21486377 h=502ff4bc4b p=3ae8ff4e38
n=21486378 h=b6a7eaea95 p=502ff4bc4b
n=21486379 h=5344bdb194 p=b6a7eaea95
n=21486380 h=267249a681 p=5344bdb194
n=21486381 h=60927f321f p=267249a681
n=21486383 h=9fdac4c4ec p=9e3d484030
n=21486384 h=6d0a843bb7 p=9fdac4c4ec

Notice that block 21486373 appears twice? That's not a typo - it's actually happening.

You might think, "No problem, I'll just deduplicate the blocks." But wait, there's more. Looking at the full sequence, I noticed that some blocks were completely missing. Blocks 21486376 and 21486382? Gone. Vanished. Never showed up.

My first thought was to use Viem's emitOnMissed: true parameter. Surely that would catch the missing blocks, right?

n=21486397 h=85cf600b05 p=c8b7dceda0
n=21486397 h=85cf600b05 p=c8b7dceda0
n=21486399 h=54ee26bc1e p=d28c102fc5
n=21486400 h=5e6ee23e87 p=54ee26bc1e
n=21486401 h=e23caad2e0 p=5e6ee23e87
n=21486402 h=784b681ab5 p=e23caad2e0

Nope. Block 21486398 still slipped through the cracks.

If you're thinking "who cares about a few missing blocks?" - here's why you should:

Instead of relying solely on websockets, here's what you should do:

Think of it like building a safety net under your websocket subscription.

Here's what a more robust system might look like:

Conclusion

Websocket subscriptions are great for real-time data, but they shouldn't be your only source of truth. Build your system with the assumption that blocks will be missed or duplicated, and plan accordingly. Your future self (and your users) will thank you.

© 2025