Skip to main content
This page covers the errors you may encounter when using Composer and how to handle them. Composer uses the same error system as the broader LI.FI API, and the errors documented here are contextualised for Composer-specific scenarios.

API Errors (Quote/Route Request)

When requesting a Composer quote via GET /quote or POST /advanced/routes, the API may return errors. These follow the standard LI.FI error format:
  1. HTTP status code (e.g., 200, 404, 429, 500)
  2. LI.FI error code (numeric)
  3. Error message (human-readable)

Relevant API Error Codes

CodeNameComposer Context
1001FailedToBuildTransactionErrorComposer could not build the transaction. The vault token may be invalid or the protocol may be temporarily unavailable.
1002NoQuoteErrorNo Composer route found. The vault token address may not be supported, or there’s insufficient liquidity for the requested path.
1004NotProcessableErrorThe request cannot be processed. Check that all parameters are valid.
1005RateLimitErrorToo many requests. Implement backoff and retry. See Rate Limits.
1007SlippageErrorPrice impact exceeds slippage tolerance. Increase the slippage parameter or reduce the amount.
1009TimeoutErrorRequest timed out. Retry the request.
1011ValidationErrorInvalid parameters. Check that fromChain, toChain, fromToken, toToken, and fromAmount are valid.
For the complete list of API error codes, see Error Codes.

Tool Errors

The API may also return tool-specific errors describing issues with the underlying protocols. These use the ToolError format:
interface ToolError {
  errorType: 'NO_QUOTE';
  code: string;
  action: Action;
  tool: string;
  message: string;
}

Relevant Tool Error Codes

CodeDescriptionComposer Context
NO_POSSIBLE_ROUTENo route found for this actionThe vault token may not be supported, or the source/destination chain combination is not available
INSUFFICIENT_LIQUIDITYThe tool’s liquidity is insufficientNot enough liquidity to complete the swap portion of the Composer flow
TOOL_TIMEOUTThe third-party tool timed outThe underlying protocol or DEX timed out. Retry the request.
AMOUNT_TOO_LOWAmount is too low to transferIncrease fromAmount. Composer routes may have higher minimums due to multiple steps.
AMOUNT_TOO_HIGHAmount exceeds available liquidityReduce fromAmount or split into multiple transactions.
FEES_HIGHER_THAN_AMOUNTFees exceed the transfer amountIncrease fromAmount so it covers gas and protocol fees.
TOOL_SPECIFIC_ERRORThe third-party tool returned an errorThe target protocol returned an error. Check that the vault is accepting deposits.

Example: Handling Tool Errors

try {
  const quote = await axios.get('https://li.quest/v1/quote', { params });
} catch (error) {
  if (error.response?.data?.errors) {
    for (const toolError of error.response.data.errors) {
      console.error(`Tool: ${toolError.tool}`);
      console.error(`Code: ${toolError.code}`);
      console.error(`Message: ${toolError.message}`);

      switch (toolError.code) {
        case 'NO_POSSIBLE_ROUTE':
          // Vault token may not be supported
          console.log('Check that the toToken is a supported vault token address.');
          break;
        case 'INSUFFICIENT_LIQUIDITY':
          // Try a smaller amount
          console.log('Try reducing the fromAmount.');
          break;
        case 'AMOUNT_TOO_LOW':
          // Increase the amount
          console.log('Increase the fromAmount.');
          break;
        case 'TOOL_TIMEOUT':
          // Retry
          console.log('Retrying...');
          break;
      }
    }
  }
}

Transaction Failures

Pre-Execution Simulation Failure

Composer simulates the entire execution path before returning a quote. If simulation fails, the API returns an error instead of a transaction that would revert onchain. This protects users from wasting gas on failed transactions. Common simulation failure causes:
  • The vault is not accepting deposits (paused, full, or restricted)
  • The token path involves incompatible tokens
  • Insufficient liquidity in the swap path

Onchain Transaction Revert

In rare cases, a transaction may revert onchain even after passing simulation (e.g., due to mempool front-running or rapid state changes between simulation and execution). If this happens:
  1. The user’s tokens remain in their wallet (for same-chain atomic transactions)
  2. Gas fees for the reverted transaction are still consumed
  3. Retry with a fresh quote to get updated simulation results

Cross-Chain Failure Modes

Cross-chain Composer flows have two phases. Each phase is atomic within its chain, but the overall flow is eventually consistent.

Status Values

Poll GET /v1/status to track cross-chain Composer transactions. The status values are:
StatusDescription
NOT_FOUNDTransaction doesn’t exist or not yet mined
INVALIDHash is not tied to the requested tool
PENDINGTransfer is still in progress
DONETransaction completed successfully
FAILEDTransfer failed

Substatus Values

When Status is PENDING

SubstatusDescription
WAIT_SOURCE_CONFIRMATIONSWaiting for source chain confirmations
WAIT_DESTINATION_TRANSACTIONWaiting for destination transaction
BRIDGE_NOT_AVAILABLEBridge API is unavailable
CHAIN_NOT_AVAILABLESource/destination chain RPC unavailable
REFUND_IN_PROGRESSRefund in progress (if supported)
UNKNOWN_ERRORStatus is indeterminate

When Status is DONE

SubstatusDescription
COMPLETEDTransfer was successful
PARTIALOnly partial transfer completed
REFUNDEDTokens were refunded

When Status is FAILED

SubstatusDescription
NOT_PROCESSABLE_REFUND_NEEDEDCannot complete, refund needed
OUT_OF_GASTransaction ran out of gas
SLIPPAGE_EXCEEDEDReceived amount too low
INSUFFICIENT_ALLOWANCENot enough token allowance
INSUFFICIENT_BALANCENot enough token balance
EXPIREDTransaction expired
UNKNOWN_ERRORUnknown or invalid state
REFUNDEDTokens were refunded

Handling Cross-Chain Failures

const status = await axios.get('https://li.quest/v1/status', {
  params: { txHash, fromChain, toChain },
}).then(r => r.data);

switch (status.status) {
  case 'DONE':
    if (status.substatus === 'COMPLETED') {
      console.log('Composer deposit completed successfully.');
    } else if (status.substatus === 'PARTIAL') {
      console.log('Partial completion: bridged tokens may be on destination chain but not deposited.');
    } else if (status.substatus === 'REFUNDED') {
      console.log('Tokens were refunded to source chain.');
    }
    break;

  case 'FAILED':
    if (status.substatus === 'SLIPPAGE_EXCEEDED') {
      console.log('Slippage exceeded. Retry with higher slippage tolerance.');
    } else if (status.substatus === 'INSUFFICIENT_ALLOWANCE') {
      console.log('Insufficient allowance. Approve tokens before retrying.');
    } else if (status.substatus === 'NOT_PROCESSABLE_REFUND_NEEDED') {
      console.log('Transfer cannot complete. Refund will be processed.');
    } else {
      console.error('Transfer failed:', status.substatus, status.substatusMessage);
    }
    break;

  case 'PENDING':
    console.log('Still in progress:', status.substatus);
    break;
}
For the full status reference, see Transaction Status Tracking.

Common Composer Issues

IssueCauseResolution
No routes returnedtoToken is not a supported vault token addressVerify the address against the Supported Protocols list
Simulation failedVault is paused, full, or not accepting depositsCheck the protocol’s status directly
Transaction revertedState changed between simulation and executionRetry with a fresh quote
Cross-chain stuck in PENDINGBridge is slow or congestedWait and continue polling. Check the bridge’s own status page if it remains stuck.
Partial completionBridge succeeded but destination action failedUser has tokens on destination chain. They can retry the deposit directly.