Errors
Most integration errors come from a mismatched send function, an incorrect first-transfer flag, invalid LayerZero options, or a stale quote.
Core errors
| Error | Cause | Client action |
|---|---|---|
InvalidAddress() | A required address is zero. | Validate token and contract addresses. |
InvalidAmount() | The amount is zero, the Vault received zero tokens, or a payload amount is invalid. | Require a positive amount and check token behavior. |
InvalidDestination() | Destination or recipient data is invalid. | Validate the EID and recipient. |
InvalidOriginal() | The original token or decoded asset identity is invalid. | Re-read token identity and contract code. |
InvalidSender() | A Router-only callback was called by another account. | Do not call internal delivery methods. |
InvalidCompose() | Composition fields are inconsistent. | For a plain transfer, use zero composer, zero gas, and 0x. |
InvalidFee() | Native value differs from the current quote. | Re-quote with identical arguments. |
NotRepresentation() | sendOFT received an unknown token. | Call oftToOriginal and use the correct send method. |
RepresentationMustUseSendOFT() | An Omniasset was passed to an original-token method. | Switch to quoteSendOFT and sendOFT. |
WithdrawFailed() | A native-fee withdrawal failed. | Operational error; normal sends do not call this path. |
Router and LayerZero errors
| Error | Cause | Client action |
|---|---|---|
InvalidEndpoint() | An endpoint ID is unknown or local. | Use a supported destination EID. |
InvalidPeer(eid, peer) | The remote sender is not the active trusted peer. | Confirm the supported route and deployment. |
MessageTooLarge() | The encoded transfer exceeds the route limit. | Reduce optional message data. |
MessageAlreadyConsumed(guid) | The delivery was already executed. | Treat it as idempotently complete. |
FailedMessageNotFound(guid) | No cached failure exists for that GUID. | Refresh the message state. |
FailedMessageHashMismatch() | Cached message data does not match. | Re-read the failure from the Router. |
InvalidExecutionOptions() | LayerZero options contain an unsupported type, value, or native drop. | Rebuild type-3 options from LayerZero. |
InsufficientLayerZeroGas(providedGas, requiredGas) | Receive gas is below the current minimum. | Read the current gas getter, add margin, and re-quote. |
InsufficientComposeGas(providedGas, requiredGas) | Optional composition gas is too low. | Raise the compose gas or remove composition. |
The Router also defines configuration-only errors such as PeerAlreadySet, ActivationPeriodTooShort, OnlyEndpoint, OnlyOmnisea, and OmniseaAlreadyBound. A normal transfer integration should never call the functions that emit them.
Decode custom errors
With viem, include errors in the ABI and use decodeErrorResult when your client receives revert data:
import { decodeErrorResult } from "viem";
const decoded = decodeErrorResult({
abi: omniseaAbi,
data: revertData,
});
console.log(decoded.errorName, decoded.args);Wallet and RPC providers wrap revert data differently. Walk the provider error cause chain before falling back to a generic message.
Retry versus resubmit
- A source transaction revert means no transfer started. Fix the inputs and submit a new transaction.
- A confirmed source transaction with
MessageFailedmeans the destination payload is cached. Do not send the original transfer again. Retry or restore the existing GUID. - A message already marked consumed must not be replayed.
See Transfer lifecycle for the recovery paths.