Skip to content

fix: nil pointer dereference panic in RegularWorker.checkContinuity + add panic recovery to worker goroutines #60

@anhthii

Description

@anhthii

Bug Report

Summary

The indexer crashes with a nil pointer dereference panic in checkContinuity() when an RPC call fails (e.g., HTTP 429 rate limit). Additionally, worker goroutines lack panic recovery, so any panic crashes the entire process instead of being handled gracefully.

Stack Trace

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0xb68bfc]

goroutine 227 [running]:
github.com/fystack/multichain-indexer/internal/worker.checkContinuity(...)
  /app/internal/worker/regular.go:293
github.com/fystack/multichain-indexer/internal/worker.(*RegularWorker).processRegularBlocks(0x4000322600)
  /app/internal/worker/regular.go:134 +0x57c

First observed: 2026-03-01T00:11:44Z
Trigger: Alchemy RPC returned HTTP 429 (monthly capacity limit exceeded) for block 74589534, causing a nil Block in the results.

Root Cause

1. Nil pointer dereference in checkContinuity (internal/worker/regular.go)

In processRegularBlocks(), the loop at line 145 skips results where res.Block == nil via continue. However, the continuity check at line 158-159 always references results[i-1]:

if i > 0 && rw.isReorgCheckRequired() {
    if !checkContinuity(results[i-1], res) {  // results[i-1].Block may be nil!

If results[i-1] was a failed block (skipped via continue), its Block field is nil. checkContinuity then dereferences prev.Block.Hash → panic.

2. No panic recovery in worker goroutines

  • RegularWorker.Start() launches go rw.run(...) with no recover()regular.go:65
  • CatchupWorker.Start() launches go cw.runCatchup() with no recover()catchup.go:72
  • Catchup parallel workers also lack recovery — catchup.go:207

Any panic in these goroutines takes down the entire indexer process.

Fix Plan

Fix 1: Track the index of the last successfully processed result and use that for the continuity check instead of blindly using results[i-1].

Fix 2: Add defer recover() with error logging to all worker goroutines (BaseWorker.run, CatchupWorker.runCatchup, and catchup parallel workers) so a panic is caught, logged, and the worker can restart rather than crashing the process.

Impact

  • Severity: Critical — crashes the entire indexer process
  • Affected chains: EVM and BTC (chains with reorg detection enabled)
  • Reproduction: Occurs when an RPC provider returns errors (429, timeout, etc.) for one block in a batch while other blocks succeed

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions