DevelopersError Reference

Error reference

Every error you can hit while integrating with Noether, in one place: the HTTP errors the gateway returns, how failed on-chain transactions surface in API responses, and the complete contract error code tables for the market, Trader Vaults, and referral contracts. Bookmark this page and search by error name or code.

All examples below are against the live gateway at https://noetherapi-production.up.railway.app (Stellar testnet).

Gateway HTTP errors

The gateway returns JSON error bodies with a machine-readable error field (or a Fastify validation shape for schema failures). Summary first, exact bodies below.

Statuserror valueWhereMeaning
400FST_ERR_VALIDATION (in code)Any endpointRequest params or body failed schema validation
400unsupported_assetPOST /v1/orders/prepareAsset symbol is not in the supported list
400simulation_failedPOST /v1/orders/prepareSoroban simulation rejected the operation before signing
400submission_rejectedPOST /v1/tx/submitRPC rejected the transaction at submission
401missing_bearerAuthed endpointsNo or invalid Authorization header
401malformed_bearerAuthed endpointsBearer token missing the : separator
401stale_timestampAuthed endpointsOptional X-Timestamp header outside ±30 s of server time
401invalid_credentialsAuthed endpointsUnknown or revoked key, or wrong secret
401invalid_signaturePOST /v1/keysBad, expired, or reused challenge; wrong signature; fee-bump transaction; wrong operation
403not_in_betaPOST /v1/keysWallet address is not on the closed-beta allowlist
404— (Fastify default)Unknown routeNo such path
404Unknown assetGET /v1/markets/{asset}, GET /v1/markets/{asset}/priceAsset not supported
404vault_not_foundGET /v1/vaults/{id}No Trader Vault with that id
404unknown_codeGET /v1/referral/lookupReferral code does not resolve
404no_codeGET /v1/referral/infoAddress never registered a referral code
404key_not_foundDELETE /v1/keys/{keyId}Key does not exist, belongs to someone else, or is already revoked
429rate_limitedAny endpoint except /v1/health and /docsRate limit exceeded for your tier
451region_restricted/v1/orders*, /v1/tx* onlyTrading blocked in your jurisdiction (configuration-dependent)
502rpc_errorPOST /v1/orders/prepare, POST /v1/tx/submitSoroban RPC unreachable or transport failure
503try_again_laterPOST /v1/tx/submitRPC transaction queue is full — retry shortly

400 — validation and preparation failures

Schema validation failures use Fastify’s built-in shape. Example (invalid candle interval):

{
  "statusCode": 400,
  "code": "FST_ERR_VALIDATION",
  "error": "Bad Request",
  "message": "querystring/interval must be equal to one of the allowed values"
}

POST /v1/orders/prepare adds two of its own:

{"error": "unsupported_asset", "asset": "XYZ"}
{"error": "simulation_failed", "message": "Simulation failed: ..."}

A simulation_failed at prepare time usually means the trade would revert on chain — insufficient collateral, a paused market, a contract error. Read the message: it often contains the underlying contract error. See how on-chain errors surface below.

401 — authentication failures

Authed endpoints expect Authorization: Bearer <keyId>:<secret> in a single header. See Authentication for the full scheme. The four failure bodies:

{"error": "missing_bearer"}
{"error": "malformed_bearer", "hint": "use Bearer <keyId>:<secret>"}
{"error": "stale_timestamp"}
{"error": "invalid_credentials"}

stale_timestamp only occurs if you send the optional X-Timestamp header (unix seconds) and it drifts more than 30 seconds from server time. Key issuance (POST /v1/keys) has its own 401:

{"error": "invalid_signature"}

Causes: the challenge expired (5-minute TTL), was already used, the signature does not verify against the claimed address, the transaction is a fee-bump, or the first operation is not the expected manageData op carrying the challenge bytes. Challenges are also held in gateway process memory, so a gateway restart voids outstanding challenges — request a fresh one and retry.

403 — closed beta

API key issuance is currently gated to early-access wallets. A non-allowlisted address gets:

{
  "error": "not_in_beta",
  "message": "API key issuance is currently restricted to early-access wallets. Contact the team to request access."
}

The gate applies at key issuance only. Public endpoints stay public, and a key you already hold keeps working. Check gating state without auth via GET /v1/keys/beta-status.

404 — not found

Unknown routes return Fastify’s default:

{"message": "Route GET:/v1/nope not found", "error": "Not Found", "statusCode": 404}

Resource-specific 404 bodies:

{"error": "Unknown asset", "asset": "FOO"}
{"error": "vault_not_found", "id": 999}
{"error": "unknown_code", "code": "NOSUCH"}
{"error": "no_code", "address": "GDA4..."}
{"error": "key_not_found"}

Note the asymmetry: GET /v1/markets/{asset} and GET /v1/markets/{asset}/price return 404 for unknown assets, but GET /v1/candles does not — it returns 200 with an empty candles array instead.

429 — rate limited

Limits are per fixed 60-second window aligned to the wall-clock minute: 60 requests/min unauthenticated (per IP), 600 requests/min with a standard API key (per key). Every rate-limited response carries X-RateLimit-Tier and X-RateLimit-Remaining headers; /v1/health and /docs are exempt. Sending a valid bearer key on any endpoint — even a public one — moves you to your key’s higher bucket.

On breach you get a Retry-After header (seconds until the window resets) and:

{"error": "rate_limited", "retry_after_sec": 37}

Back off until retry_after_sec elapses, then resume.

451 — region restricted

The trading endpoints (/v1/orders* and /v1/tx*) can be geo-restricted. When the restriction applies you get HTTP 451:

{
  "error": "region_restricted",
  "message": "Trading is not available in your jurisdiction. See the Terms of Service (restricted persons)."
}

This response is configuration-dependent — treat it as a possible response on the trading endpoints and handle it terminally (do not retry). Read-only endpoints, authentication, and /v1/health are outside the geo-guarded surface and are not geo-restricted.

5xx — upstream failures

{"error": "rpc_error", "message": "..."}

HTTP 502: the gateway could not reach Soroban RPC. Retry with backoff.

{
  "error": "try_again_later",
  "retryable": true,
  "hash": "...",
  "message": "RPC transaction queue is full — resubmit the same signed XDR shortly"
}

HTTP 503, with Retry-After: 2: the RPC transaction queue is full. Resubmit the same signed XDR after the delay — POST /v1/tx/submit is idempotent, so resubmitting is safe and returns the prior result if the transaction already landed.

How on-chain errors surface

Noether contracts fail with typed Soroban contract errors — on the wire they look like Error(Contract, #22). The gateway decodes these for you at two points in the trading flow:

At prepare time. POST /v1/orders/prepare simulates the transaction before returning the unsigned XDR. If the contract would revert, you get 400 simulation_failed and never need to sign anything.

At submit time. POST /v1/tx/submit decodes contract errors from the transaction’s diagnostic events into a structured contractError object:

{
  "hash": "85895449a4...",
  "status": "FAILED",
  "contractError": {"code": 22, "name": "InsufficientCollateral"},
  "resultXdr": "AAAA..."
}

A transaction rejected before inclusion returns 400 submission_rejected with the same optional contractError field. In both cases contractError is null when the failure is not a contract error (resource budget exhaustion, a Soroban auth failure, and so on) — inspect resultXdr for those.

Two things to know when decoding:

  • The gateway’s decode map mirrors the shared NoetherError table below, with one gap: code 43 (DepositCapExceeded) is missing from the gateway’s map today. It — like any code the gateway does not recognize — decodes as "UnknownContractError" with the raw code preserved, so match on code, not name.
  • Each contract has its own code space. NoetherError covers the market contract (and the shared vault, oracle shim, and router errors). Trader Vault (FactoryError) and referral (ReferralError) codes overlap numerically with the low NoetherError codes — disambiguate by which contract your transaction invoked.

Most common while integrating

  • #30 PriceStale — the oracle price for the asset is older than 60 seconds and you are on a risk-increasing path (opens, strict order checks). Closes and liquidations are never blocked by staleness. The Noether Router avoids this on the app by relaying a fresh signed price in the same transaction; via the API, retry — prices are refreshed continuously.
  • #22 InsufficientCollateral — collateral below the 10 USDC minimum (100000000 raw), or the open fee consumed all of it. Send collateral as a 7-decimal fixed-point string.
  • #21 InvalidLeverage — leverage must be an integer from 1 to 10 on the current deployment.
  • #23 PositionTooLarge — position size (collateral × leverage) above the $100,000 cap.
  • #82 OpenInterestCapExceeded — the open would push the asset past its per-side open-interest cap (25% of Liquidity Vault AUM) or the aggregate reservation cap (70% of AUM). Reduce size or wait for open interest to unwind.
  • #81 PriceDeviationTooHigh — the fresh price moved more than 1% from the last good price recorded within the past 600 seconds; opens halt, closes still work.

Parameter details are on Trading mechanics.

Market and shared contract errors (NoetherError)

Shared by the market contract, the Liquidity Vault, the Noeracle shim, and the Noether Router. Codes are grouped in ranges by category.

General (1–19)

CodeNameMeaning
1NotInitializedContract not initialized
2AlreadyInitializedinitialize called twice
3UnauthorizedCaller not authorized (raised by the router; the market and vault use Soroban auth panics instead)
4PausedOperation blocked while the contract is paused (liquidations and order cancellation stay available)
5InvalidParameterBad input — also covers an invalid time-in-force mode, a bad take-profit limit price, and closing a non-cross position through the cross-margin path
6OverflowArithmetic overflow
7DivisionByZeroDivision by zero (for example, an entry price of 0 in a PnL calculation)

Position (20–29)

CodeNameMeaning
20PositionNotFoundNo position with that id
21InvalidLeverageLeverage outside the 1 to 10 range
22InsufficientCollateralCollateral below the 10 USDC minimum, or the open fee consumed all collateral
23PositionTooLargePosition size above the $100,000 maximum
24NotPositionOwnerCaller is not the position’s trader
25InsufficientMarginDefined but not raised by the current market code

Oracle (30–39)

CodeNameMeaning
30PriceStalePrice older than 60 seconds on a risk-increasing path (opens, strict order checks); closes and liquidations are exempt
31InvalidPricePrice is zero or negative; also an unknown asset symbol in the shim or router feed lookup
32OracleUnavailableOracle not responding (raised by the shim, not the market)

Vault (40–49)

CodeNameMeaning
40InsufficientLiquidityThe Liquidity Vault cannot cover the request: withdrawal above balance, a withdrawal that would undercut reserved payouts for open positions, a position reservation above the vault’s physical USDC balance, or short NOE inventory
41InvalidAmountAmount is zero or negative
42InsufficientBalanceUser NOE balance too low for the withdrawal
43DepositCapExceededPer-account guarded-launch deposit cap reached

Liquidation (50–54)

CodeNameMeaning
50NotLiquidatablePosition is healthy — or liquidate was called on a cross-margin position (use the cross-account path)
51LiquidationFailedDefined but not raised by the current code

Funding (55–59)

CodeNameMeaning
55FundingIntervalNotElapsedapply_funding called before 3,600 seconds have elapsed since the last application

Order (60–75)

CodeNameMeaning
60OrderNotFoundNo order with that id
61OrderNotPendingOrder already executed or cancelled
62OrderNotTriggeredPrice has not reached the order’s reference price
63SlippageExceededDefined but never returned — on a slippage breach the order is cancelled (status CancelledSlippage, collateral refunded) instead of the transaction reverting
64NotOrderOwnerCaller is not the order’s trader
65InvalidTriggerPriceTrigger price is zero or negative, or a stop-loss/take-profit trigger sits on the wrong side of the entry price
66InvalidSlippageToleranceSlippage tolerance is 0 or above 10,000 bps
67OrderAlreadyExistsThe position already has an attached order of that type (one stop-loss, one take-profit, one trailing stop per position)
68InvalidLimitPriceDefined but not raised — stop-limit uses #65 for a bad limit price and take-profit uses #5
69InvalidTrailingPercentTrailing percentage is 0 or above 5,000 bps (50%)
70PostOnlyViolationA Post-Only order would fill immediately at placement

Cross margin (76–82)

CodeNameMeaning
76CrossMarginInsufficientBalanceWithdrawal above the cross-margin pool balance
77CrossMarginInsufficientFreeMarginThe open or withdrawal would leave account equity at or below maintenance margin (plus the new position’s collateral, for opens)
78CrossMarginNotLiquidatableAccount equity is at or above maintenance margin
79CrossMarginNoPositionsTrader has no open cross-margin positions
80CrossMarginOrderNotSupportedStop-loss, take-profit, and trailing stops cannot attach to cross-margin positions
81PriceDeviationTooHighFresh price moved more than 1% versus the last good price recorded within the past 600 seconds; opens halt, closes and liquidations still work
82OpenInterestCapExceededThe open would exceed the per-asset per-side open-interest cap (25% of vault AUM) or the aggregate reservation cap (70% of AUM)

Trader Vault errors (FactoryError)

Raised by the Trader Vaults (vault factory) contract. These share numbers with low NoetherError codes — attribute by contract.

CodeNameMeaning
1AlreadyInitializedinitialize called twice
2NotInitializedContract not initialized
3InvalidParameterBad input (for example, a direction that is not 0 or 1)
4InvalidNameVault name empty or longer than 64 characters
5VaultNotFoundUnknown vault id
6NotLeaderA leader-only call made by an address that is not the vault’s leader
7NotAdminDefined; the admin check uses Soroban auth instead
8AmountMustBePositiveAmount or shares is zero or negative (or a deposit would mint 0 shares)
9InsufficientSharesBurning more shares than owned, or more than the total supply
10InsufficientBalanceTrade collateral or payout exceeds the vault’s USDC balance
11LeaderMinimumViolatedThe action would break the 5% leader minimum-holding rule (checked on every deposit, every withdrawal, and after each leader open)
12PausedVault is paused by its leader or the admin
13OverflowChecked-math overflow
14NavCalculationFailedNegative inputs to the NAV calculation
15NoFeesToClaimFee claim with NAV at or below the high-water mark

A note on #11: because the leader must always hold at least 5% of shares, an outside depositor cannot make the first deposit into an empty vault (the leader seeds it first), and total outside deposits are bounded relative to the leader’s stake. See Trader Vaults.

Referral errors (ReferralError)

Raised by the referral contract.

CodeNameMeaning
1AlreadyInitializedinitialize called twice
2NotInitializedContract not initialized
3NotAdminDefined; the admin check uses Soroban auth instead
4NotMarketDefined; the market check uses Soroban auth instead
5InvalidParameterBps above 5,000, or negative volume
6CodeTooShortCode shorter than 3 characters
7CodeTooLongCode longer than 16 characters
8CodeAlreadyTakenCode already exists (codes are globally unique and case-sensitive)
9AlreadyHasCodeOne code per address
10UnknownCodeCode does not resolve to a referrer
11AlreadyHasReferrerReferee is already bound to a referrer — bindings are permanent
12SelfReferralCode owner and referee are the same address
13InsufficientVolumeDefined but not enforced on-chain — the gateway checks the minimum-volume requirement before code creation
14NothingToClaimClaimable balance is zero or negative
15OverflowChecked-math overflow

Next steps