Skip to main content
Version: Endpoint V2

Debugging Messages

Message Lifecycle

Every LayerZero message goes through the following high-level steps:

  • Source Block Confirmations: The message remains pending until the source chain finalizes the required number of block confirmations. This ensures that the transaction is securely committed on the source chain.

  • DVN/Verification: Each Decentralized Verifier Network (DVN) independently verifies the message and submits an on-chain transaction attesting to its validity.

  • Committer/Commit Verification: Once all required DVN attestations are available, a Committer submits a transaction to aggregate and commit these verifications on the destination chain. This step guarantees that the message has been sufficiently validated.

  • Executor/Message Execution: Finally, an Executor submits a transaction to deliver and execute the verified message on the destination chain.

Debugging Messages using LayerZero Scan

After a LayerZero message is successfully submitted on the source chain, it can be tracked using LayerZero Scan. OApps can monitor the full message lifecycle, including delivery status and configuration details, directly through the LayerZero Scan.

For programmatic access, the LayerZero Scan Swagger API provides a comprehensive set of endpoints to query, track, and analyze cross-chain messages and transactions. With the LayerZero Scan API, you can retrieve messages using parameters such as transaction hash, OApp address, wallet address, status, pathwayId, GUID, and more.

Message Statuses Overview

Message status is an important indicator of what’s happening with your message. Always check the status first before diving deeper into debugging—it can save significant time. Below are the main statuses on LayerZero Scan:

Delivered

The message has been successfully sent and received by the destination chain.

info

The Delivered status indicates that the lzReceive function was successfully invoked when the message arrived at the destination chain. However, in some cases, the subsequent lzCompose execution may fail. If there is a Composer implemented, review the lzCompose message status on LayerZero Scan and follow the provided instructions to retry message.

Inflight

The message is currently being transmitted between chains and has not yet reached its destination.

  • If DVN verification has not yet started, verify the number of block confirmations required on the source chain (configured in the receiveConfig). DVNs will only begin verification after the source transaction has reached the configured confirmation threshold.

  • If the required confirmations are reached but the message remains in an inflight state, the issue may fall into one of the following categories:

    • One or more DVNs have not yet submitted their verification for the message.

    • All DVNs have submitted verifications, but the Committer has not yet aggregated and committed them on the destination chain.

    • The Committer has successfully committed the verifications, but the Executor has not yet executed the message.

      • If a pathway has Ordered Execution enabled, a message cannot be executed until all preceding messages have been fully verified. Check the Message Execution Options in LayerZero Scan to confirm whether the ordered execution option is set to true and identify the first unverified message in the sequence, as subsequent messages will not be executed until it is verified.

      • At the stage of pending execution, execution can also be triggered manually by calling on the Endpoint's lzReceive function. This call is permissionless and can be initiated by anyone. Alternatively, LayerZero Scan provides a built-in option to execute the message directly through its interface.

If the message remains inflight and is not delivered within the expected timeframe, contact community support for further assistance.

Failed

The message is delivered at destination chain but the message execution failed.

LayerZero Scan displays any errors encountered during message execution. If the underlying issue can be resolved, the message can then be retried through the interface.

See Message Execution for more details.

Blocked

The message is prevented from progressing due to configuration issues and requires manual intervention or updates to resolve.

A "Blocked" message usually points to configuration issues:

  • NotInitializable:

    This status typically indicates that the destination OApp is either missing trusted peer settings or the pathway has not been properly initialized.

    Common causes:

    • Incorrect peer configuration: Ensure that setPeer() is correctly called on both the source and destination chains during deployment. Double-check that the address format and endpoint ID are accurate.

    • Pathway not initialized correctly: Confirm that allowInitializePath() is properly implemented in your OApp contract. Learn more: allowInitializePath.

  • Dst OApp Not Found: The receiver is not a valid contract.

  • DVN Mismatch: All DVN providers must be the same on source and destination. See DVN Mismatch for more details.

  • Dead DVN: This configuration includes a Dead DVN. See Dead DVN for more details.

  • Block Confirmations Mismatch: Outbound confirmations must be ≥ inbound confirmations. See Block Confirmation Mismatch for more details.

Confirming

The system is currently validating transaction finality. This status may appear at any stage of the message lifecycle and typically represents a transitional state before progressing to the next step.

Malformed Command

The command is malformed. The status is only applied to lzRead message. To debug, see Debugging Malformed or Unresolvable Commands for more details.

Unresolvable Command

The command is unresolvable. This status is only applied to lzRead message. To debug, see Debugging Malformed or Unresolvable Commands for more details.

For Malformed Command and Unresolvable Command, an OApp must call skip() to unblock the message pathway. If skip() is not invoked, subsequent messages will not be delivered. See Skipping Nonce for more details.

To troubleshoot common errors in lzRead messages, See debugging for more details.

SIMULATION_REVERTED

This status can be found in the LayerZero Scan API as a sub status inside the destination section, indicating the lzReceive or lzCompose has failed on the destination chain.

General Debugging Steps

If the message was not sent successfully

Quick triage

  • Confirm the transaction:
    • Did the source chain transaction finalize? (Check explorer receipt status and logs.)
  • Look for packet emission
    • Verify whether the expected LayerZero “PacketSent” event is emitted on the source chain.
  • Capture context:
    • Source and destiantion chain
    • OApp addresses
    • send params
    • DVN and Exeutor Configs

Identify the revert / error trace

Run a trace (Foundry/Tenderly/Trace on explorer) and map to the failing contract and error codes.

Common errors (causes & fixes):

Please set your OApp's DVNs and/or Executor

  • Cause: This error occurs during getFee, indicating your OApp configuration is missing the required DVN and/or Executor settings.
  • Fix: Set valid DVNs and/or executor in the OApp configs.

InsufficientFee()

  • Cause: required.nativeFee > suppliedNativeFee or required.lzTokenFee > suppliedLzTokenFee; or msg.value lower than the quoted amount.
  • Fix: Call the quote function first, pass the exact fee, and forward enough msg.value.

NativeAmountExceedsCap()

  • Cause: Requested native drop on destination exceeds the configured native drop cap.
  • Fix: Reduce requested airdrop amount in options or raise the cap in the Executor/destination config (owner action).

InvalidWorkerOptions()

  • Cause: Worker options is malformed.
  • Fix: Rebuild options via the Options Builders.

Unauthorized()

  • Cause: This error normally occurs at the wiring step. The call is not made by the OApp or an approved delegate.
  • Fix: Use the permissioned wallet to sign the transactions.

Unsorted()

  • Cause: DVNs array contains duplicates or is not strictly sorted.
  • Fix: Deduplicate and sort DVN addresses deterministically before passing; keep canonical order in code.

UnsupportedEid()

  • Cause: The pathway is not connected.
  • Fix: Use the correct destination EID, verify chain mapping, and contact the support team if a pathway is not wired.

Configuration & connectivity checklist

  • Delegate & Ownership
  • Peers:
    • peers are set on both source and destination chain
    • addresses & EIDs match, and in correct format
  • Message Libraries:
    • sendLibrary and receiveLibrary are set to expected addresses/versions.
  • DVNs:
    • DVN provider set(s) exist
    • Identical provider(s) on source and destination
    • Contain no LZ Dead DVNs unless intended
  • Executor:
    • Executor address is set as intended
    • Message size doesn't exceed Executor limit
    • Native drop amount doesn't exceed cap
  • Message Exeuction Options:
    • Ensure enforcedOptions and/or extraOptions is present;
    • Profiling destination gas for lzReceive and/or lzCompose to determine the gas units applied in the message execution options
  • Connected pathways:
    • Confirm whether a pathway is fully connected

If these pass but the send still fails, simulate the send with the same params and use the error trace to narrow the root cause.

If the message was sent

Now the message is visible on LayerZero Scan. Use Scan to locate the message and walk the lifecycle.

  • Get transaction hash on the source chain

  • Start with Message Status on Scan

    • Statuses map directly to lifecycle stages and tell you where to focus first:
  • Identify which stage the message is at (decision tree)

    • No DVN confirmations yet?

      • Check source confirmations vs. threshold; verify DVN set correctly.
    • DVNs verified, but not committed?

      • Check Executor config and contact support team.
    • Committed, but not Executed?

    • lzReceive succeeded but lzCompose failed?

      • Inspect lzcompose revert reason
      • retry lzCompose.

Retrieve Retry Parameters via LayerZero Scan API

Use the LayerZero Scan API to fetch a message bundle by source tx hash and inspect the destination execution. If execution failed, the destination section includes failedTx, which typically points to an Executor alert call (e.g., lzReceiveAlert or lzComposeAlert). The alert transaction’s call data contains the parameters required to retry lzReceive or lzCompose.

Endpoint

Base URL: https://scan.layerzero-api.com/v1
Method: GET /messages/tx/{tx}

tx: source-chain transaction hash (hex string)

Response Shape

Each response returns a data array of message objects:

  • pathway: source/destination networks and EIDs, sender/receiver address, application information
  • source: transaction details and status on source chain
  • verification: DVN verification transactions and the committer/sealer transaction for committing verifications
  • destination: execution status on the target chain (including failed txs)
  • config: ULN configurations (Confirmations, DVNs, Executor) in effect for this pathway
  • status: overall message status
  • guid, created timestamps and updated timestamp

In the API response, look for failedTx for the transactions that contains the eror for lzReceive message. Examine the revertReason in the destination section to identify the root cause.

API Response Example in the destination section:

"destination": {
"nativeDrop": {
"status": "N/A"
},
"lzCompose": {
"status": "N/A"
},
"failedTx": [
{
"txHash": "0xa6cf8347a8679866955fbf83175ccc3191f592c27865e89ce69bf99d71542b53",
"txError": "CouldNotParseError(string) 0x",
"blockHash": "0xa3130ed1fbb60b45bd99638a07f415892118442e72d5be6eda58214a6a41c610",
"blockNumber": 23266956,
"revertReason": "0x"
}
],
"status": "SIMULATION_REVERTED"
}

How to get retry parameters

  • Call GET /messages/tx/{tx} with the source tx hash. In data[0].destination.failedTx, take the txHash (usually an lzReceiveAlert or lzComposeAlert transaction that the executor called to signal the failure).
  • Fetch that destination transaction and inspect.
  • If revertReason is empty (0x), it commonly indicates out-of-gas or a contract-level revert without a reason string.
  • For custom error, decode the selector using 4byte directory.
  • Function selector & args of the alert call input; it embeds everything needed to re-invoke lzReceive/lzCompose
  • Alternatively, all the information can also be retrieved directly from the scan API.

Skip/Clear/Burn/Nilify

skip: Called by the receiver to skip verification and delivery of a nonce.

clear: Called by the receiver to skip a nonce that has been verified.

nilify: Called by the receiver to temporarily invalidate a nonce. nilify can be used to proactively invalidate maliciously generated packets from compromised DVNs. Message can be re-executed.

burn: Called by the receiver to delete and skip a nonce. burn can be used if a faulty Security Stack commits an invalid hash to the endpoint, or if an OApp needs to clear a nilified nonce. Message can not be re-executed.

See: Skip/Clear/Burn/Nilify on EVM and Skip/Clear/Burn/Nilify on Solana for full semantics and usage.