# Errors

Each entry: what it means, and what to do. Contract errors are Solidity custom errors; decode the revert data with the contract's ABI (the ABIs in the repo, `packages/sdk/src/abi/margin/`, include every error; liquidation-book errors come from the hook's address). A reverted transaction changes nothing except the gas spent.

## API errors

Every error of the indexer API has this shape:

```json
{ "error": "period must be one of 24h, 7d, 30d, all", "code": "invalid_param", "field": "period", "action": "Use one of 24h, 7d, 30d, all, or omit it for 7d." }
```

| HTTP | `code` | Meaning | Action |
|---|---|---|---|
| 400 | `invalid_param` | A query or path parameter is malformed (`field` names it) | Fix the value as `action` says; do not retry unchanged |
| 404 | `not_found` | The referral code, route or file does not exist | Check the spelling; codes are lowercase |
| 429 | — | Too many requests from your IP (about 10/s for the API, 5/s for GraphQL) | Wait at least a second, then retry with backoff; cache `/launches` for 15 s |
| 200 with `errors` | — | GraphQL query error (unknown field, bad filter) | Read the message; field names are in [openapi.json](https://atomic.green/agents/openapi.json) |
| 5xx, timeout | — | Indexer unavailable | Retry with backoff; read the chain directly meanwhile |

## Spot trading (AtomicTradeRouter, curve, pool)

| Error | Meaning | Action |
|---|---|---|
| `SlippageExceeded` | The price moved past your minimum out | Quote again; widen slippage only if you accept the worse price |
| `DeadlinePassed` | The pool swap landed after `deadline` | Quote again with a new deadline |
| `CurveGraduated` | The curve is closed | Re-read `phase`; trade the pool when it is 2 |
| `VenueNotAllowed` (through Permit2: `TRANSFER_FROM_FAILED`) | The token may not move to this pool, or the router paid it before the swap | Use the token's own `poolKey` and a router that swaps first ([trade.md](https://atomic.green/agents/trade.md)); do not retry unchanged |
| `NotReadyToGraduate` / `AlreadyGraduated` | Graduation call at the wrong moment | Not needed for trading; re-read `phase` |
| `InsufficientLiquidity` | Not enough tokens left on the curve or in range | Trade a smaller amount, or the pool after graduation |
| `InsufficientInputAmount` / `ZeroAmount` | Amount is zero or too small to produce output | Use a larger amount |
| `NativeValueMismatch` | `value` does not equal the ETH amount in | ETH input: `value = amountIn`; ERC-20 input: `value = 0` |
| `UnexpectedNativeValue` | ETH sent to an ERC-20 trade | Send `value = 0` |
| `NativeInputNeedsNoPermit` | `…WithPermit` used with ETH input | Use `swapExactInSingle` with `value` |
| `UnknownFactory` | The `factory` argument is not one the router trades | Use the launch's `factory` from the indexer row |
| `UnknownLaunch` | The token is not a launch of that factory | Check the token address and its `factory` |
| `UnknownHook` / `UnknownPool` | The pool key is not an Atomic pool | Use `poolKey` from the indexer row (correct `hooks`, `fee`, `tickSpacing`) |
| `HopMismatch` / `UnknownHopPool` | Pay-with-another-token route is not approved | Pay with the pair asset instead |
| `FeeCreditOutOfGas` | Gas limit too low for the fee bookkeeping | Raise the gas limit (estimate + 30%, at least +1,000,000) |
| `SafeERC20FailedOperation`, `ERC20InsufficientAllowance`, `ERC20InsufficientBalance` | Token transfer failed: missing approval or balance | Approve the router (or Permit2) for the amount; check balance |
| `TooManyLiquidations` | The swap would cross more than 24 liquidation levels | Split it into smaller swaps |
| `TransferFailed`, `NativeTransferFailed` | Sending ETH or tokens to the recipient failed | Use a recipient that accepts ETH |
| `ReentrancyGuardReentrantCall` | Call re-entered the contract | Do not call the router from inside another router call |

Permit2 (`0x000000000022D473030F116dDEE9F6B43aC78BA3`): `InvalidNonce` (nonce already used: pick a new random one), `SignatureExpired` (deadline passed: sign again), `InvalidSigner` / `InvalidSignature` (wrong signer, chain id, token, amount or spender in the signed message), `InsufficientAllowance` (approve Permit2 for the token first).

## Leverage (AtomicMarginTrading, the hook and its liquidation book)

| Error | Meaning | Action |
|---|---|---|
| `NoLiquidationLevel(reason)` | No safe liquidation level for this size: 1 locked liquidity too thin, 2 level closer than 5%, 3 would endanger open positions, 5 the liquidation chain would be too long for one swap | Lower the margin or the leverage; check `maxLeverage` and `previewOpen` first |
| `InvalidLeverage` | Leverage outside x1.1–x10 or not a 0.1x step | Use 11 000–100 000 bps in steps of 1 000, at most `maxLeverage` |
| `LeverageNotEnabledYet(enabledAt)` | The token's snipe-tax window has not ended | Wait until `enabledAt` |
| `UnknownMarket` | The token has no leverage market (not graduated, or no lending pool) | Check `marketOf(token).ok` |
| `TradingDisabled` | New positions are paused by the protocol; closes and claims still work | Wait |
| `BelowMinNotional` | `margin × leverage` below the minimum (`minNotional(quote)`, and 0.1% of the pool's locked quote depth) | Raise the margin or the leverage |
| `MarginBelowFee` | The margin does not cover the entry fee | Raise the margin |
| `NativeValueMismatch` | `value` is not the margin (ETH open) or the exact funding (`extend`) | Send exactly the amount; for `extend` read `fundingQuote` again |
| `InvalidParam` | Bad open parameters (TP range or bounds) | Rebuild the TP range with `tpRange` and the bounds from a fresh `previewOpen` |
| `InvalidRange` | The TP range is not entirely past the price on the profit side | Use `tpRange(token, isLong, notional, targetTick, wide)` |
| `RangeReached` | `editTakeProfit` after the price reached the range | Close instead (`closeTakeProfit` or `closePosition`) |
| `SlippageExceeded` | Long bought fewer than `minTokensOut`, or short needed more than `maxTokensIn` | Preview again and resend |
| `DeadlineExpired` | Landed after `deadline` | Preview again with a new deadline |
| `BookFull`, `BucketFull` | Too many positions at that liquidation level or side | Change size or leverage, or wait |
| `IncompleteFill`, `InsufficientFunds` | The pool could not fill the entry, or the margin does not cover it | Smaller size |
| `FloorPerBlock` | A liquidation level was armed in this block | Retry in a few seconds |
| `CloseWouldNotCoverDebt(available, debt)` | Selling now does not repay the loan | The owner cannot close by hand; the liquidation level still protects the loan |
| `TakeProfitNotFilled` | `closeTakeProfit` before the whole range is passed | Wait, or close by hand |
| `NotExpired` | `closeExpired` before `expiry`, or by someone else within an hour after it | Wait |
| `PriceMovedFromReference` | `closeExpired` with the price over 500 ticks on the position's losing side of the reference | Wait for the reference to catch up; the owner can `closePosition` with a limit |
| `NotLiquidated` | `settleLiquidation` on a position not liquidated | Check `getPosition(id).status` |
| `NotOpen` | The position is already closed or liquidated | Read its status; claim any payout |
| `NotPositionOwner` | Only the owner may close by hand, edit the TP or extend | Send from the owner |
| `NothingToClaim` | `claimable(you, asset)` is 0 | Check the other asset (ETH vs the token) |
| `EthTransferFailed` | Sending ETH to you failed | Claim to an address that accepts ETH |

## Lending pool

| Error | Meaning | Action |
|---|---|---|
| `WithdrawNotReady(readyAt)` | `executeWithdraw` before `readyAt` | Wait until `readyAt` |
| `InsufficientLiquidity(available, needed)` | That much is lent out now | Wait, or cancel and request at most `freeLiquidity(asset)` |
| `InsufficientShares` | More shares than you hold | Read `sharesOf(you, asset)` |
| `NotRequestOwner` | Another wallet's withdrawal request | Use your own `requestId` |
| `InvalidAsset` | Asset other than 0 (quote) or 1 (token) | Use 0 or 1 |
| `ZeroAmount` | Zero deposit or zero shares | Use a positive amount |
| `NativeValueMismatch`, `InexactTransfer` | ETH `value` differs from `amount`, or a token that takes a transfer fee | Send exactly `amount` |

## Creating a token (factory, AtomicLaunchAndBuy)

| Error | Meaning | Action |
|---|---|---|
| `LaunchFeeNotPaid` | `value` is not exactly the launch fee (plus the buy amount for ETH launch-and-buy) | Read `launchFee()` and send exactly it |
| `LaunchEconomicsMismatch` | Terms changed since you read `previewLaunchEconomics` | Read it again, rebuild params, simulate again |
| `NotWhitelisted` | Launches are limited and this wallet is not allowed | `canLaunch(wallet)` must be true; nothing else helps |
| `InvalidTokenParams` | Name or symbol is empty | Fill both |
| `CreatorTaxTooHigh` | `creatorTaxBps` above `maxCreatorTaxBps()` | Lower it (max 1000 = 10%) |
| `InvalidLaunchConfigId` / `LaunchConfigDisabled` | Config index out of range or disabled | Use an `id < launchConfigCount()` with `enabled` true |
| `PairTokenNotApproved` | The pair ERC-20 is not allowed | Use ETH (zero address) or an approved pair (`approvedPairTokens`) |
| `ExemptionListTooLong` | More than 32 snipe-tax exemptions | Shorten the list |
| `CombinedFeeTooHigh`, `CurveFeeTooHigh` | Fee settings over the cap | Lower `creatorTaxBps` |
| `NotApprovedLauncher` | Launch-and-buy contract not wired to this factory | Use the `AtomicLaunchAndBuy` of the same stack in deployments.json |
| `RefundFailed` | Could not refund unspent ETH | Send from an address that accepts ETH |
| `GraduationSeedNotViable` | The Uniswap pool could not be created at this price | Report it; do not retry in a loop |
| `LaunchDeployerNotSet`, `LaunchDependenciesNotWired`, `GraduationExecutorNotSet` | The stack is not fully set up | Use the active stack in deployments.json |

## Creator fees, vesting, referrals

| Error | Meaning | Action |
|---|---|---|
| `NoBalance` / `InsufficientBalance` | Nothing (or less) to claim in the escrow | Check `balanceOf` / `balanceOfToken` first |
| `NotCreatorFeeRecipient` | Only the current fee recipient may do this | Send from the fee recipient wallet |
| `NotBuybackController` | Only the creator side may switch buyback | Send from the fee recipient wallet |
| `NothingToClaim` | Referral reward already claimed up to `cumulativeAmount` | Wait for the next epoch |
| `InvalidProof` | Proof does not match the published root | Fetch fresh `claims` from `/v1/referrals/{address}` |
| `InvalidCode` / `CodeTaken` / `CodeAlreadySet` | Code format wrong (`[a-z0-9_]{3,20}`), taken, or the wallet already has one | Pick another code; one per wallet |
| `InvalidReferrer` / `AlreadyBound` | Self, zero or looping referrer; or the wallet is already bound | Nothing to do; binding is permanent |

Errors starting with `Ownable`, `NotFactory`, `NotFeeSweepOperator`, `NotPublisher`, `NotBinder`, `NotLaunchForwarder`, `NotTrading`, `NotDelegated`, `NotSelf`, `NotOwner` are admin-only or internal paths: an agent should never call those functions.
