> ## Documentation Index
> Fetch the complete documentation index at: https://docs.layerzero.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Debugging Messages

> Debug LayerZero crosschain messages. Track message lifecycle, verify delivery status, and troubleshoot common issues. Crosschain development with LayerZero...

## 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.

<Info>
  **OFT atomicity:** For a standard OFT, the token debit (burn or lock) is atomic with the `PacketSent` event from the LayerZero Endpoint. Tokens cannot be debited without a corresponding message being emitted — if the send fails, the entire transaction reverts and no tokens are debited. On the destination side, the token credit (mint or unlock) is atomic with `PacketDelivered`. Custom OApps may implement non-atomic behavior in `_lzSend` or `_lzReceive`, but this is not the default OFT behavior.
</Info>

* **[DVN](../glossary#dvn-decentralized-verifier-network)/Verification**: Each Decentralized Verifier Network (DVN) independently verifies the message and submits an onchain transaction attesting to its validity.

* **[Committer](../glossary#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](../glossary#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](https://layerzeroscan.com). OApps can monitor the full message lifecycle, including delivery status and configuration details, directly through the [LayerZero Scan](../../tools/layerzeroscan/overview).

For programmatic access, the [LayerZero Scan API](../../tools/layerzeroscan/api) lets you look up messages by 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](../../developers/evm/composer/overview) implemented, review the `lzCompose` message status on LayerZero Scan and follow the provided instructions to [retry message](#retry-message).
</Info>

### *Inflight*

The message is waiting for source block confirmations, verification, or execution on the destination chain.

* 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](../../tools/sdks/options#orderedexecution-option) 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](https://discord.com/invite/ktbvm8Nkcr) 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](#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](../../tools/integration-checklist#set-peers-on-every-pathway).

* **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](../../developers/evm/configuration/dvn-executor-config#dvn-mismatch) for more details.

* **Dead DVN**: This configuration includes a Dead DVN. See [Dead DVN](../../developers/evm/configuration/dvn-executor-config#dead-dvn) for more details.

* **Block Confirmations Mismatch**: Outbound confirmations must be ≥ inbound confirmations. See [Block Confirmation Mismatch](../../developers/evm/configuration/dvn-executor-config#block-confirmation-mismatch) for more details.

### *Confirming*

The Executor has submitted the destination transaction and the system is waiting for it to reach finality on the destination chain. This is a transitional state before the message is marked as `Delivered`.

### *Malformed Command*

The command is malformed. The status is only applied to lzRead message. To debug, see [Debugging Malformed or Unresolvable Commands](../../developers/evm/lzread/read-cli#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](../../developers/evm/lzread/read-cli#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](../../developers/evm/troubleshooting/debugging-messages#skipping-nonce) for more details.

To troubleshoot common errors in `lzRead` messages, See [debugging](../../developers/evm/lzread/overview#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**
  * Verify the owner and delegate address
  * [Understand their respective permissions](../../faq#whats-the-difference-between-delegate-and-owner)
* **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](#message-statuses-overview) 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?

    * If it is `orderedExecution`, inspect the first unverified prior message.
    * Inspect revert transaction and revert reason
    * Fix root cause
    * Retry the message
      * [Retry messages on EVM](../../developers/evm/troubleshooting/debugging-messages#retry-message)
      * [Retry messages on Solana](https://github.com/LayerZero-Labs/devtools/blob/main/examples/oapp-solana/tasks/solana/retryPayload.ts)

  * `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:

```json wrap theme={null}
"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](https://www.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](../../developers/evm/troubleshooting/debugging-messages#skipping-nonce) and [Skip/Clear/Burn/Nilify on Solana](../../tools/sdks/solana-sdk#skip-a-message) for full semantics and usage.
