LCX Liberty. American DeFi. Your keys. Your assets. Your control.
Errors
The response envelope, and the codes worth branching on.
The envelope
Every response has the same outer shape, success or failure. Branch on success and then on code, rather than on the status alone.
{
"success": false,
"code": "no_route",
"message": "No route found for this pair at this size."
}message is written to be read by a person. In most cases it is the best thing you can put in front of a user verbatim. error carries the same string as code and exists only so older tooling keeps working; read code in new integrations.
Some codes carry extra fields beside the envelope. insufficient_liquidity is the richest: when the engine refuses a size it also searches for the sizes that would have worked, and reports them so your user does not have to guess.
{
"success": false,
"code": "insufficient_liquidity",
"message": "This pair is indexed, but our liquidity is too thin at this size: the best route we found loses 96.19% of value. About 1.4 UNI trades at roughly 4.5% impact; the most we can quote at all is about 31.25 UNI (49.7% impact).",
"bestImpactPct": 96.19,
"venues": ["uniswap-v2", "uniswap-v3"],
"maxAmountIn": "31250000000000000000",
"maxAmountInImpactPct": 49.671,
"comfortableAmountIn": "1400000000000000000",
"comfortableImpactPct": 4.478
}maxAmountIn is the largest input the engine verified it can still quote, and comfortableAmountIn is the largest it verified at no more than 5% impact. Both are raw units of tokenIn, both were re-quoted before being reported, and both can be null or absent: a pair can be too thin at any size, in which case only the generic message remains. venues names the venues of the single best route that was refused, not everything the search considered.
Codes
| Code | Status | What to do |
|---|---|---|
INVALID_API_KEY | 401 | Fix the key. Retrying will not help. |
RATE_LIMITED | 429 | Back off and retry with jitter. |
QUOTA_EXCEEDED | 429 | Upgrade or wait for the month to roll over. |
TEMPORARILY_BLOCKED | 429 | Wait for Retry-After, then call with a valid key. |
no_route | 400 | The pair cannot be routed. Not retryable at this size. |
insufficient_liquidity | 422 | Routable, but not at this size. The body carries maxAmountIn and comfortableAmountIn when the engine could verify working sizes; offer those instead of asking the user to guess. |
pricing_unreliable | 409 | A pool behind this pair reports prices the engine refuses to trust (a stale or manipulated book). No size is safe; retry after the pool's state refreshes rather than shrinking the amount. |
QUOTE_EXPIRED | 410 | Re-quote and show the new price. Do not retry the build. |
price_moved | 400 | The pool moved past the floor the quote promised. Re-quote. |
impact_too_high | 422 | The trade would move the price by 15% or more. Not built at this size; offer a smaller one. |
transfer_tax | 422 | The token keeps a share of every transfer and has no pool that pays out in full, so the swap would fail. Not retryable; the message names the token and the share. |
transfer_blocked | 422 | The token refuses the transfer out of its pools that a swap needs. Not retryable. |
bridge_too_small | 422 | Cross-chain: the amount does not cover the bridge's cost. The message names the minimum. |
bridge_too_large | 422 | Cross-chain: above what the bridge fills at once. The message names the limit; send less or split it. |
one_tx_unavailable | 400 | A cross-chain bundle asked for as one transaction cannot be one here. Read oneTransaction from /v1/multi/xcorridors, or build the two transactions. |
decimals_mismatch | 400 | The decimals you sent are not the token's; the message names the right figure. Send amountIn in base units, or leave decimals out. |
decimals_required | 400 | A human amount of a token we hold no decimals for. Send amountIn in base units, or pass decimals. |
slippage_mismatch | 400 | The built floor no longer matches the quote. Re-quote; do not relax it. |
store_unavailable | 503 | Our index for this chain is outside its freshness window, so we will not build against it. The message names which check failed. Retry shortly. |
route_not_executable | 400 | The route contains a step the deployed router cannot run. Re-quote. |
router_not_deployed | 503 | The network's router holds no code yet, so nothing was built. The network is not open for swaps; /v1/chains says when it is. |
too_large_for_block | 400 | The route or bundle needs more gas than one block of this network holds. A smaller amount, fewer tokens or a simpler pair fits. |
native_is_a_token | 400 | This network's gas coin is itself a token (nativeIsToken in /v1/chains). Send that token's address instead of the native placeholder. |
reserve_balance | 422 | Selling the native coin would leave the wallet under the balance its network makes every account keep for gas (Monad: 10 MON). The message says how much this wallet can sell. Sell less; retrying cannot help. |
bad_recipient | 400 | The recipient cannot be paid: not an address, the zero address, one of our routers, or a system address where the output would leave the network. Send to the wallet itself. |
PERMIT_UNSUPPORTED | 400 | Fall back to a plain approve. |
quote_unavailable | 503 | The engine could not price this in time. Ours, not yours. Retry shortly. |
Retrying
Retry 5xx, network failures and RATE_LIMITED with jittered backoff. Do not retry any other 4xx. Resending a request the server has already refused will get the same answer, and it delays the moment you notice the bug.
Jitter is not decoration. Without it, every client that trips the same limit retries in lockstep and trips it again.
A failed request costs nothing, so the quota is not the reason to be careful here. Correctness is.