monad-ops · incidents

Recovery-path assertion stall class

Source-traced incident class observed on monad testnet · open archive · 2 confirmed cases · last seen 2026-05-18

What it is

A class of stall on a monad full node where monad-execution aborts with a MONAD_ASSERT on the recovery path — specifically when monad-bft is restarted while monad-execution remains alive, and BFT replays proposals whose block_id is still in monad-execution's in-memory block_cache window.

Two cases have been confirmed by independent operators so far. The trigger line spans at least monad v0.14.1 and v0.14.3 — this is a stable fragility of the recovery path, not a regression in a particular release.

Operator-visible signature

Source trace

The assertion is in cmd/monad/runloop_monad.cpp in the public category-labs/monad repository. The relevant block at line 216 (as of the time of writing):

MONAD_ASSERT(
    block_cache
        .emplace(
            block_id,
            BlockCacheEntry{...})
        .second);

block_cache is an unordered map keyed by the 32-byte block_id. emplace().second == false means the key was already in the map — i.e., the same block_id was proposed for execution twice. The cache is bootstrap-filled on startup, sliding-window-pruned after finalize, and lives for the lifetime of the monad-execution process.

When monad-bft is restarted independently, BFT re-establishes IPC to the still-live monad-execution and replays proposals from its WAL / blocksync catch-up. Some of those replayed proposals carry block_id values already in monad-execution's block_cache window. Re-emplacing triggers the assertion. SIGABRT, core dump, dead service.

A second operator observed the same class on monad v0.14.1 on a different line of the same file; the framing "recovery-path assertion in runloop_monad.cpp" therefore covers multiple sites in the same file rather than a single line.

Mitigations (in place on this node)

What is still unknown

Contribute an observation

If you have observed a SIGABRT of monad-execution on the recovery path after a monad-bft restart, regardless of monad version, please file an issue at github.com/rustemar/monad-ops with:

Operator identities and node-specific details remain private unless you explicitly opt in — only the anonymised case-class counters are surfaced back into this page.

Scope and limitations