Skip to main content
Confirmation depth sets how many source-chain blocks a DVN waits before it attests to a message. It makes a reorg unlikely to invalidate a message the destination has already accepted. It does not make it impossible. This page covers what happens when a reorg runs deeper than the confirmation depth you configured. Many messages in that situation recover with no action from you. A smaller set becomes permanently undeliverable, and no endpoint function can revive them.

How a reorg breaks nonce agreement

Each pathway keeps a nonce on both chains. The source endpoint increments outboundNonce on every send. The destination endpoint tracks lazyInboundNonce, the last nonce it has settled, and stores a payload hash for each verified nonce. A deep reorg breaks the agreement between the two:
  1. Your OApp sends a message on the source chain. The endpoint increments outboundNonce to N.
  2. The DVNs wait for your configured confirmations, then attest. The destination verifies nonce N, and the executor delivers it.
  3. The source chain reorgs past the block that held the send. That block is no longer canonical, so the chain discards the storage write and outboundNonce falls back to N-1.
  4. The next send on the source chain takes nonce N again.
The destination has already consumed N. The source is about to reuse it. What happens to that replacement message depends entirely on how far the destination got before the reorg.

Recovery depends on execution, not verification

The destination endpoint decides whether a nonce can be verified again with one rule:
Aptos, Sui, and Initia apply the same rule. Solana reaches the same outcome through a different mechanism. Executing a message closes its payload hash account, and the init_verify instruction requires the nonce to be greater than the inbound_nonce held on the pathway’s Nonce account. A consumed nonce therefore has no account left to re-verify and cannot be opened again.

Verified but not executed: the message recovers

If the destination verified nonce N but no one executed it, the payload hash is still stored and lazyInboundNonce has not moved. The second clause holds, so the replacement message can verify. Verifying it overwrites the stored payload hash. The orphaned message becomes unexecutable and the replacement executes in its place. The pathway delivers exactly one message for nonce N and loses nothing. This is the ordinary re-verification path, and it needs no intervention.

Executed, cleared, or skipped: the message is lost

If the destination executed nonce N, lazyInboundNonce is at or above N and execution deleted the payload hash. Both clauses fail, so verify reverts with LZ_PathNotVerifiable. This state is permanent. There is no timeout after which the message becomes deliverable, and no number of retries changes the outcome. Calling clear or skip on a nonce leaves it in the same dead state, because both advance lazyInboundNonce past it.

Replacement messages reuse the GUID

A GUID is derived from the nonce and the pathway, with no input from the payload or the block:
A replacement message that reuses nonce N therefore carries the same GUID as the message the reorg removed, even though its contents differ. If your off-chain accounting treats the GUID as a unique message identifier, it will merge two different messages into one record. Key your replay protection and reconciliation on something other than the GUID, because GUID uniqueness does not survive a reorg.

How many messages you lose

Only the reused nonces fail. Once outboundNonce climbs back above the destination’s lazyInboundNonce, messages verify and deliver normally again. Once the reorg settles, the destination counter is ahead of the source counter. The distance between them is the number of undeliverable sends:
If the source counter is the higher of the two, the pathway has not diverged and nothing is lost. Suppose the destination executed nonces 1 through 3 and the reorg returned outboundNonce to 2. The gap is 3 - 2 = 1. The next send takes nonce 3 and is lost. The send after that takes nonce 4 and delivers normally.

Detect the divergence

Nothing surfaces this automatically, so monitor for it. Read outboundNonce(sender, dstEid, receiver) on the source endpoint and lazyInboundNonce(receiver, srcEid, sender) on the destination endpoint for each pathway you operate. In normal operation the source counter is at or above the destination counter. If the source counter falls below the destination counter, the pathway has diverged and every send until it catches up will fail to verify. Also alert on LZ_PathNotVerifiable reverts from verify on the destination. A healthy pathway that starts producing them has diverged.

Respond to a reorg

  1. Stop sending on the affected pathway. Every send while the source counter sits below the destination counter debits the sender and cannot be delivered.
  2. Record the gap between the two counters. That is how many sends are unrecoverable.
  3. Reconcile the message that executed before the reorg. The destination applied it and the source no longer records the send, so an OFT has credited tokens on the destination with no matching debit on the source.
  4. Advance outboundNonce past the destination’s lazyInboundNonce before you resume real traffic.
    • Sending is the only way to do this. The endpoint increments outboundNonce inside _outbound, which only send calls, and it exposes no function to set the counter directly.
    • Every send you use to close the gap pays fees and is never delivered.
    • If the gap is large, deploying a new OApp on either side gives you a fresh channel, because the nonce is keyed by the sender and receiver addresses.
  5. Re-issue the lost payloads as new messages once the counters agree.

Prevent it

Set confirmations above the worst reorg depth the source chain has produced, not its typical depth, and pin the value explicitly on both sides of the pathway. The per-chain floors are in Confirmation depth. Nothing you do after the fact substitutes for this, because the stranded messages cannot be recovered. Two design choices reduce what a single reorg can cost you. Per-message or per-window transfer caps bound the value that one incident can strand. A pause on the pathway lets you stop debiting users as soon as you detect the divergence, which is what keeps the loss from growing while you investigate. For high-value pathways, note that the damage becomes permanent only at execution. A pathway that delays or gates destination execution, for example by requiring an operator to confirm before the executor runs, stays in the recoverable case for longer.