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

# Error Codes

> The JSON-RPC error shape and the full Derive v3 application error catalog.

Every failed request returns a JSON-RPC 2.0 error object, whether the call was made
over WebSocket or HTTP POST. The `error` object always has three fields:

```json theme={null}
{
  "id": "1",
  "jsonrpc": "2.0",
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": "expiry: value out of range"
  }
}
```

<ResponseField name="code" type="integer" required>
  The numeric error code. Negative codes are JSON-RPC / transport-level; positive codes are Derive application errors
  (see the catalog below).
</ResponseField>

<ResponseField name="message" type="string" required>
  A short, stable human-readable summary.
</ResponseField>

<ResponseField name="data" type="string | null" required>
  Optional detail (e.g. the offending field or protocol reason). Always present on the wire — it is `null` when there is
  no detail.
</ResponseField>

## JSON-RPC base codes

The standard JSON-RPC 2.0 codes cover malformed or unroutable requests before any
application logic runs.

| Code | Name | Message | When it fires |
| - | - | - | - |
| −32700 | `parse_error` | Error parsing message | Request body is not valid JSON |
| −32603 | `internal_error` | Internal error | Any uncaught or internal server failure |
| −32602 | `invalid_params` | Invalid params | Params fail validation |
| −32601 | `method_not_found` | Method not found | Unknown RPC method |
| −32600 | `invalid_request` | Invalid Request | Not a valid JSON-RPC request object |

<Warning>
  **Internal errors are redacted.** For code **−32603**, the server always returns `message: "Internal error"` and
  `data: null` on the wire — any underlying detail is kept server-side and never leaked to clients. Treat −32603 as
  "retry or contact support," not as a description of what went wrong.
</Warning>

## Transport & session codes

| Code | Name | Message | When it fires |
| - | - | - | - |
| −32000 | `rate_limit_exceeded` | Rate limit exceeded | Per-wallet or per-instrument limit hit |
| −32000 | `custom_rate_limit_error` | *(caller-supplied)* | A method-specific rate-limit rejection |
| −32100 | `concurrent_ws_client_exceeded` | Number of concurrent websocket clients limit exceeded | Too many concurrent WebSocket connections |
| 401 | `unauthorized` | Unauthorized | Missing or invalid authentication |
| 403 | `forbidden` | Forbidden | Authenticated but not permitted |
| 403 | `restricted_region` | You are in a restricted region that violates our terms of service. | Request originates from a geoblocked region |

See [Rate limits](/rate-limits) for how the two-tier limiter works and how to read
your live limits, and [Authentication](/authentication/session-login) for the session-login and
action-signing layers behind the 401/403 and 14xxx codes.

## Application error catalog

Application errors use positive codes grouped by numeric range. Codes are stable;
gaps within a range are reserved.

<Note>
  Internal **8xxx** codes (e.g. counterparty/feed diagnostics) are intentionally omitted from this reference — they are
  server-side signals, not client-actionable, and are excluded from public docs.
</Note>

### 9xxx — Confirmation timeouts and backend availability

For **9000** and **9001** the order was accepted but a downstream confirmation did not
arrive in time; query order state before resubmitting. **9002** and **9003** are different:
the request never took effect, so it is safe to retry as-is.

| Code | Name | Message | When it fires |
| - | - | - | - |
| 9000 | `order_confirmation_timeout` | Order confirmation timeout | Order confirmation timed out |
| 9001 | `engine_confirmation_timeout` | Engine confirmation timeout | Matching-engine confirmation timed out; order dropped |
| 9002 | `backend_unavailable` | Backend temporarily unavailable, retry | A read backend is restarting, catching up on prices, or at capacity. Nothing was executed; retry shortly |
| 9003 | `settlement_too_far_behind` | Settlement is too far behind, retry later | The exchange paused new requests while on-chain settlement catches up. Nothing was executed; retry shortly |

### 10xxx — Accounts, transfers & margin

Rejections from account, session-key, and subaccount-level constraints before an
order reaches the book.

| Code | Name | Message | When it fires |
| - | - | - | - |
| 10001 | `asset_not_erc20` | Asset is not an ERC20 token | Deposit/withdraw/transfer of a non-ERC20 asset |
| 10003 | `same_account_transfer` | Sender and recipient subaccount IDs are the same | Self-transfer |
| 10004 | `multiple_currencies_not_supported` | Multiple currencies not supported | Mixed-currency request rejected |
| 10006 | `max_session_keys_per_wallet` | Maximum number of session keys per wallet reached | Session-key cap reached |
| 10007 | `max_assets_per_subaccount_exceeded` | Maximum number of assets per subaccount reached | Per-subaccount asset cap reached |
| 10010 | `pmrm_only_supports_quote_asset` | PMRM only supports USDC asset collateral. Cannot trade spot markets. | PMRM subaccount tried to trade spot |
| 10015 | `pm2_only_support_single_currency_options_and_perps` | PortfolioMargin2 supports multiple collaterals but only options and perps of the same currency | PM2 cross-currency options/perps |
| 10016 | `pm2_does_not_support_this_collateral` | PortfolioMargin2 does not support this collateral | PM2 unsupported collateral |

### 11000–11039 — Orders, balances & matching

Order-lifecycle rejections from the matching engine, plus the balance-level guards
that reject a debit before it is applied.

| Code | Name | Message | When it fires |
| - | - | - | - |
| 11000 | `insufficient_funds` | Insufficient funds | Insufficient margin/funds for the order |
| 11006 | `order_does_not_exist` | Does not exist | Cancel/query of an unknown order |
| 11007 | `self_crossing_disallowed` | Self-crossing disallowed | Order would cross your own resting order |
| 11008 | `post_only_reject` | Post only order cannot cross the market | Post-only order would match immediately |
| 11009 | `zero_liquidity_for_taker_order` | Zero liquidity for market or IOC/FOK order | No liquidity within the limit price |
| 11011 | `order_invalid_signature_expiry` | Invalid signature expiry | Expiry outside the allowed validity window |
| 11012 | `invalid_amount` | Invalid amount | Order amount invalid |
| 11013 | `order_invalid_limit_price` | Invalid limit price | Limit price invalid |
| 11014 | `fok_not_filled` | Fill-or-kill not filled | FOK order could not be fully filled |
| 11015 | `mmp_frozen` | MMP frozen | Market-maker protection frozen for the subaccount/currency |
| 11017 | `non_unique_nonce` | Non unique nonce | Nonce already used |
| 11018 | `order_invalid_nonce` | Invalid nonce date | Leading nonce digits are not a valid UTC-second timestamp |
| 11019 | `too_many_orders` | Open orders limit exceeded | Open-order cap per subaccount reached |
| 11020 | `negative_erc20_balance` | Negative ERC20 balance | Wrapped ERC20 balance would go negative |
| 11021 | `instrument_not_live` | Instrument is not live | Instrument deactivated or expired |
| 11022 | `reject_timestamp_exceeded` | Reject timestamp exceeded | Order arrived after its `reject_timestamp` |
| 11023 | `max_fee_too_low` | Max fee order param is too low | `max_fee` below the required minimum |
| 11024 | `reduce_only_not_supported` | Reduce only not supported with this time in force | Reduce-only requires market/IOC/FOK |
| 11025 | `reduce_only_reject` | Reduce only reject | Reduce-only order would increase the position |
| 11027 | `undergoing_liquidation` | Subaccount undergoing liquidation | Subaccount is being liquidated |
| 11028 | `replace_order_filled_amount_mismatch` | Replaced order filled amount does not match expected state. | Replace saw an unexpected filled amount |
| 11029 | `oi_cap_exceeded` | Trade or transfer rejected: open interest cap would be exceeded | Open-interest cap for the manager exceeded |
| 11030 | `fee_consumes_amount` | Fee consumes entire amount | Fee is ≥ the transfer/withdraw amount |
| 11031 | `withdrawal_rounds_to_zero` | Withdrawal rounds to zero | Net withdrawal rounds to zero in native decimals |
| 11032 | `transfer_below_min` | Transfer below minimum | New-subaccount funding below the minimum |
| 11033 | `transfer_not_whitelisted` | Transfer recipient not whitelisted | Recipient not on the sender's whitelist |
| 11034 | `withdrawals_blocked_insolvent_auction` | Withdrawals blocked by insolvent auction | Withdrawals paused during an insolvent auction |
| 11035 | `non_increasing_nonce` | Non increasing nonce | Signed-action nonce is not strictly increasing |
| 11039 | `lending_borrows_exceed_supply` | Lending pool borrows exceed supply | Pool has lent out more than it holds; debit uncoverable |
| 11046 | `withdraw_destination_unsupported` | Withdrawals are not forwarded to this chain | `register_withdraw_address` for a chain with no route |
| 11047 | `invalid_withdraw_recipient` | Recipient is not a valid address on the destination chain | Bad recipient, or an EVM recipient that is not the wallet |

### 11050–11055 — Trigger orders

Stop / trigger-order specific rejections.

| Code | Name | Message | When it fires |
| - | - | - | - |
| 11050 | `trigger_order_already_cancelled_or_expired` | Trigger order was cancelled between the time worker sent order and engine processed order | Trigger cancelled before it could be processed |
| 11051 | `invalid_trigger_price` | Trigger price must be higher than current price for stop orders and vice versa | Trigger price on the wrong side |
| 11052 | `too_many_trigger_orders` | Trigger order limit exceeded (separate limit from regular orders) | Trigger-order cap reached |
| 11053 | `trigger_price_type_not_supported` | Index and last-trade trigger price types not supported yet | Only mark-price triggers are supported |
| 11054 | `cannot_replace_or_be_replaced_by_trigger_orders` | Trigger orders cannot replace or be replaced | Replace involving a trigger order |
| 11055 | `unfillable_market_trigger_order` | Market order limit\_price is unfillable at the given trigger price | Market trigger would not be crossable |

<Info>
  A parallel **11150–11155** code range for trigger-order rejects appears in the reject-message mapping and may surface
  for some persisted trigger rejections. Handle trigger rejects by `name`/`message` rather than hard-coding `11050` vs
  `11150`.
</Info>

### 11100–11113 — RFQs & quotes

Request-for-quote and quote-matching rejections.

| Code | Name | Message | When it fires |
| - | - | - | - |
| 11100 | `leg_instruments_not_unique` | Leg instruments are not unique | Repeated instrument across RFQ/quote legs |
| 11101 | `rfq_not_found` | RFQ not found | RFQ query/cancel matched nothing |
| 11102 | `quote_not_found` | Quote not found | Quote query/cancel matched nothing |
| 11103 | `quote_leg_mismatch_vs_rfq` | Quote leg does not match RFQ leg | Quote legs differ from RFQ legs |
| 11104 | `quote_rfq_not_open` | Requested quote or RFQ is not open | RFQ expired, filled, or cancelled |
| 11105 | `quote_rfq_id_mismatch` | Quote references a different RFQ than requested | Quote's RFQ id differs from the one provided |
| 11106 | `rfq_invalid_counterparty` | Invalid RFQ counterparty | Counterparty unauthorized or nonexistent |
| 11107 | `quote_maker_cost_too_high` | Quote maker total cost too high | Maker cost exceeded the price bandwidth |
| 11108 | `rfq_partial_fill_pct_too_high` | RFQ partial fill percentage too high | Fill exceeds the requested total size |
| 11109 | `rfq_filled_direction_cannot_be_changed` | RFQ filled direction cannot be changed | A later fill would flip the direction |
| 11110 | `quote_taker_cost_too_high` | Quote taker total cost too high | Taker cost exceeded the orderbook execution price |
| 11111 | `rfq_disabled_for_account` | RFQ functionality is disabled for this account | RFQ disabled for the account |
| 11112 | `rfq_too_many_legs` | RFQ has too many legs | Leg count over the maximum |
| 11113 | `rfq_too_many_counterparties` | RFQ has too many counterparties | Counterparty count over the maximum |

### 12xxx — Market data

| Code | Name | Message | When it fires |
| - | - | - | - |
| 12001 | `instrument_not_found` | Instrument not found | Unknown instrument |
| 12002 | `currency_not_found` | Currency not found | Unknown currency |
| 12003 | `asset_not_found` | Asset not found | Unknown asset |

### 13000 — Subscriptions

| Code | Name | Message | When it fires |
| - | - | - | - |
| 13000 | `invalid_channels` | Invalid channels | Unknown or malformed subscription channel |

### 14xxx — Authentication & authorization

Session-login, signature, and session-key scope failures. See
[Authentication](/authentication/session-login) for the underlying scheme.

| Code | Name | Message | When it fires |
| - | - | - | - |
| 14000 | `account_not_found` | Account not found | Account does not exist |
| 14001 | `subaccount_not_found` | Subaccount not found | Subaccount not owned by a registered wallet |
| 14013 | `string_is_not_ethereum_address` | String is not a valid ethereum address | Malformed address |
| 14014 | `invalid_signature` | Signature invalid for message or transaction | Recovered signer does not match the expected signer |
| 14020 | `auth_header_mismatch` | The X-DeriveWallet header does not match the requested subaccount\_id or wallet | Auth header subject mismatch |
| 14021 | `ip_not_whitelisted` | IP not whitelisted | Request IP not on the whitelist |
| 14023 | `invalid_signer` | Signer in on-chain related request is not wallet owner or registered session key | Signer is neither the owner nor a registered session key |
| 14026 | `session_key_not_found` | Session key not found | Unknown session key |
| 14027 | `unauthorized_as_rfq_maker` | Unauthorized as RFQ maker | Account is not an RFQ maker |
| 14028 | `cross_currency_rfq_not_supported` | Cross currency RFQ not supported | RFQ legs span multiple currencies |
| 14030 | `session_key_expired` | Session key expired | Session key is past its expiry |
| 14031 | `unauthorized_key_scope` | Unauthorized Key Scope | Session-key scope insufficient for the action |
| 14033 | `account_not_atomic_whitelisted` | Account not whitelisted for atomic orders | Atomic order from a non-whitelisted account |
| 14035 | `session_key_already_registered` | Session key already registered | Session key already belongs to another wallet |

<Tip>
  **`14014` with signing that looks right is usually bad ABI encoding, not a bad
  signature.** Routes encode `Action.data` server-side, so your bytes never reach
  the decoder — the hashes simply disagree, naming no field.

  Send them to [`public/decode_action`](/api-reference/system/publicdecode_action)
  (no auth, executes nothing) for the decoded fields or the exact fault:

  ```
  word 2 (limit_price) is not e12-representable: downscale discards a non-zero remainder
  ```

  SDK: `await client.decodeAction('order', encodedData)`. Once the bytes decode,
  the `*_debug` routes compare EIP-712 hashes.
</Tip>

### 16xxx — Compliance

| Code | Name | Message | When it fires |
| - | - | - | - |
| 16001 | `account_disabled` | Account is disabled due to compliance violations | Account disabled by compliance |
| 16002 | `ofac_blocked` | Account is blocked due to OFAC compliance violations. | Account blocked under OFAC screening |

### 17xxx — Risk universes

| Code | Name | Message | When it fires |
| - | - | - | - |
| 17000 | `cross_universe_trade` | Instrument not supported by this manager / risk universe | Participants belong to different risk universes |
| 17001 | `unknown_risk_universe` | Unknown risk universe | Referenced risk universe does not exist |
| 17002 | `manager_cannot_risk_currency` | Risk manager has no configuration for this currency | Trading or holding a currency the subaccount's manager cannot price |
| 17003 | `asset_not_in_risk_universe` | Asset is not registered in the destination risk universe | Depositing or transferring an asset the destination cannot hold |

### 18xxx — Vaults

| Code | Name | Message | When it fires |
| - | - | - | - |
| 18007 | `vault_not_found` | Vault not found | Subaccount is not a vault |
| 18008 | `exceeded_max_user_requests` | Exceeded maximum number of pending vault requests | Too many pending deposit/withdraw requests |
| 18009 | `max_shareholder_vaults_reached` | Exceeded maximum number of shareholder vaults | Shareholder-vault cap reached |
| 18010 | `vault_closed` | Vault is closed | Vault has been fully withdrawn/closed |
| 18011 | `vault_cooldown_active` | Vault withdrawal cooldown active | Deposit→withdraw cooldown not elapsed |
| 18012 | `vault_creation_deposit_below_min` | Vault creation deposit below minimum | Curator's initial deposit below the minimum |
| 18013 | `vault_curator_stake_below_min` | Curator stake below minimum | Withdrawal would drop curator stake below the floor |
| 18014 | `vault_slippage_exceeded` | Vault quote outside slippage band | Share price outside the accepted band |
| 18015 | `vault_amount_below_min` | Vault amount below minimum | Deposit/withdraw below the per-asset minimum |
| 18016 | `vault_signature_expiry_too_long` | Vault signature expiry too far out | Expiry more than 30 days out |
| 18017 | `vault_benchmark_price_unavailable` | Vault HWM benchmark price unavailable | High-water-mark benchmark has no feed |
| 18018 | `vault_initial_share_price_too_far_from_benchmark` | Vault initial share price too far from benchmark | Initial price too far from the benchmark |
| 18019 | `vault_deposit_exceeds_margin` | Insufficient margin for vault deposit | Source subaccount cannot back the deposit |

### 19xxx — Liquidations

Rejections from `public/start_auction` and `private/liquidate`. `data` carries the
specifics, such as the actual price and the limit for 19007.

| Code | Name | Message | When it fires |
| - | - | - | - |
| 19000 | `subaccount_not_liquidatable` | Subaccount is not liquidatable | Starting an auction on an account whose maintenance margin is intact |
| 19001 | `auction_already_ongoing` | Auction already ongoing | Starting an auction on an account that already has one |
| 19002 | `auction_not_ongoing` | No ongoing auction | Bidding on an account with no open auction |
| 19003 | `auction_invalid_portion` | Invalid liquidation portion | `percent_of_acc` outside `(0, 1]` |
| 19004 | `auction_solvent_expired` | Solvent auction expired | Solvent discount decayed to zero; a new start converts it |
| 19005 | `auction_self_transfer` | Liquidation cannot transfer a subaccount to itself | Liquidatee and portion recipient are the same |
| 19006 | `auction_bidder_initial_margin_breached` | Bid would leave the bidder below initial margin | Bidder cannot carry the portion it would absorb |
| 19007 | `auction_price_limit_violated` | Auction price limit violated | Current auction price is above the bid's `price_limit` |

## Handling errors

<Tip>
  Branch on `code` for programmatic handling and surface `message` (and `data` when present) to users. Never parse
  `message` text — it is stable but treat `code` as the contract. For −32603, retry with backoff rather than inspecting
  the (redacted) body.
</Tip>


## Related topics

- [public/get_all_referral_codes](/api-reference/referrals/publicget_all_referral_codes.md)
- [Rate Limits](/rate-limits.md)
- [public/get_onchain_action_history](/api-reference/onchain-actions/publicget_onchain_action_history.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.