Error Codes#
Complete reference of Seesaw protocol error codes.
User-Facing Message Matrix#
Apps, SDKs, CLI commands, and API transaction builders should convert raw
program errors into specific recovery messages. Do not surface bare values like
Custom(68) to traders.
| Situation | Program errors or symptoms | User-facing message | Recovery action |
|---|---|---|---|
| Insufficient collateral | InsufficientBalance, transaction simulation fail | Not enough USDT to place this order | Add USDT or reduce order size |
| Insufficient shares | InsufficientBalance, InvalidRedemption | You do not have enough shares for this action | Reduce size or refresh position |
| Trading not started | TradingNotStarted, EpochNotStarted | This market is not live yet | Wait for the start snapshot |
| Trading ended | TradingEnded, EpochNotEnded where applicable | Trading has closed for this market | Claim after resolution or choose another market |
| Already settled/resolved | AlreadyResolved, MarketNotResolved | This market is already resolved or not resolved yet | Refresh market state |
| Orderbook full | OrderbookFull | The order book is full at the moment | Use a matching price or try again later |
| Bulk cancel incomplete | BulkCancelIncomplete | More orders qualify than one transaction can cancel | Use explicit six-ID batches and refresh |
| Reduced order too small | RestingNotionalTooSmall | The remaining order would be below the minimum | Cancel it fully or leave a larger remainder |
| Price outside band | OrderPriceOutOfBand | Maker price is outside the allowed band | Move price closer to the current market |
| Post-only would cross | WouldCross | Post-only order would execute immediately | Adjust price or use a regular limit order |
| Stale oracle | StaleOracle | Waiting for a fresh Pyth price | Retry after the next oracle update |
| Confidence too wide | ConfidenceTooWide | Pyth confidence is too wide for this market | Wait for market conditions to stabilize |
| Oracle not valid/trading | InvalidOracleData, InvalidPrice | Pyth data is not currently usable for this market | Retry or check the feed status |
| Wrong network/account | InvalidAccountOwner, InvalidPDA, wallet error | Wallet or account does not match this deployment | Switch network or reconnect wallet |
| Missing token account | token-account simulation failure | Required token account is missing | Create/fund the token account |
| Transaction timeout | expired blockhash, no confirmation | Transaction was submitted but did not confirm in time | Check signature, then retry if it did not land |
| RPC rate limited | HTTP 429, RPC provider error | RPC provider is rate-limiting requests | Retry with backoff or switch endpoint |
| Wallet rejection | wallet adapter rejection | Transaction was rejected in the wallet | Reopen the action and approve if still intended |
| Preparation already finished | PreallocationReceiptNotActive | This market preparation was already opened or reclaimed | Refresh the canonical market and receipt state |
| Preparation reclaim too early | PreallocationReclaimTooEarly | Only the creator can reclaim this preparation yet | Use the creator wallet or wait for the 24-hour boundary |
| Preparation does not match | PreallocationReceiptMismatch, PreallocationTargetMismatch | The saved preparation does not match this market | Rebuild from canonical receipt and market data |
| External market halted | MarketHalted | New orders are paused for this market | Cancel, withdraw, or use another allowed exit |
| Resolver unavailable | WrongResolver, ResolverNotRegistered, ResolverRevoked | This market's resolver cannot perform that action | Refresh resolver status; operators follow the wind-down runbook |
| External expiry early | ExternalMarketNotExpired | This market is not eligible for permissionless expiry yet | Retry after the displayed strict expiry time |
| Reclaim claim mismatch | ReclaimClaimBindingMismatch, ReclaimInvalidProof | Signed claim does not match this lifecycle action | Refresh witness/build context; do not rewrite the signed package |
| Retired Native Reclaim codes | ReclaimThresholdNotMet, ReclaimUnknownWitness | Reserved for ABI compatibility; no live path emits these codes | Do not retry based on these retired codes |
| Reclaim claim consumed | ReclaimClaimAlreadyConsumed | This signed lifecycle action has already completed | Refresh market and receipt state; treat satisfied state as success |
Every failed transaction surface should include the submitted signature when one exists, an explorer link, the current market state if known, and a safe retry instruction.
Overview#
Error codes are organized by category for easy identification:
Market Errors (0x1001 - 0x1012)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0x1001 | MarketExists | Market account already exists | Use existing market |
0x1002 | InvalidState | Operation not valid in current market state | Check market state before operation |
0x1003 | TradingNotStarted | Trading has not begun (start price not snapshotted) | Wait for start price snapshot |
0x1004 | TradingEnded | Trading period has ended | Cannot place new orders |
0x1005 | AlreadyResolved | Market outcome already determined | No-op, proceed to settlement |
0x1006 | MarketNotResolved | Market not yet resolved | Wait for resolution |
0x1007 | TooEarly | Operation attempted too early | Wait for appropriate time |
0x1008 | EpochNotStarted | Epoch has not started yet | Wait for t_start |
0x1009 | EpochNotEnded | Epoch has not ended yet | Wait for t_end |
0x100A | NotOwner | Caller is not the owner of the resource | Use correct wallet |
0x100B | PositionsRemaining | Unsettled positions or redeemable bearer supply remain | Settle positions and reduce every aggregate leg payout to zero |
0x100C | MarketCloseTimeout | Market close timeout has not elapsed (resolved_at + 7 days) | Wait for the 7-day timeout |
0x100D | InvalidCreator | Creator account does not match the market's creator | Use the correct creator keypair |
0x100E | VaultNotEmpty | Vault still contains funds; cannot close market | Withdraw all funds first |
0x100F | InvalidDuration | Market duration is outside allowed bounds (60s–604800s) | Use a valid duration |
0x1010 | InvalidConfidenceRatio | Confidence ratio exceeds maximum valid value (10000 bps) | Use a lower confidence ratio |
0x1011 | InvalidStateTransition | State transition is not valid from current state | Check market state before operation |
0x1012 | LedgerBalancesRemaining | Occupied trader-ledger slots retain quote or share balances | Withdraw or settle ledger balances before closing |
Market Error Examples#
// Check if market exists before interacting
try {
const market = await program.account.market.fetch(marketPda);
} catch (e) {
if (e.code === 0x1001) {
console.log('Market already exists');
}
}
// Handle trading state
if (error.code === 0x1004) {
console.log('Trading has ended for this market');
// Redirect to settlement or next market
}
Oracle Errors (0x2001 - 0x2008)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0x2001 | OracleMismatch | Pyth feed does not match market configuration | Use correct feed for market |
0x2002 | StaleOracle | Oracle price data is stale | Wait for fresh price update |
0x2003 | InvalidPrice | Oracle reported an invalid price (zero or negative) | Check feed status |
0x2004 | ConfidenceTooWide | Oracle confidence interval exceeds maximum allowed ratio | Wait for more certain price |
0x2005 | FeedIdMismatch | Pyth feed ID does not match expected feed ID stored in market | Verify feed ID |
0x2006 | InvalidOracleData | Oracle price exponent is outside valid range [-18, 18] | Check oracle data format |
0x2007 | OraclePriceJumpTooLarge | Oracle end price moved beyond the circuit-breaker bound | Wait for market to stabilize |
0x2008 | UnsupportedOracleSource | The selected source cannot use this instruction | Use the source-specific observation or Pull snapshot path |
Oracle Error Examples#
// Handle stale oracle
if (error.code === 0x2002) {
console.log('Oracle price is stale, retrying in 1 second...');
await sleep(1000);
// Retry operation
}
// Handle confidence issues
if (error.code === 0x2004) {
console.log('Price confidence too wide, market may be volatile');
// Consider waiting for better conditions
}
Order Errors (0x3001 - 0x3023)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0x3001 | InvalidQuantity | Order quantity is invalid (zero or exceeds maximum) | Use valid quantity (> 0) |
0x3002 | OrderbookFull | Order book side has reached its configured capacity | Wait for orders to clear or use IOC |
0x3003 | OrderNotFound | Order not found in the order book | Order may have been filled or cancelled |
0x3004 | WouldCross | PostOnly order would immediately match (cross the spread) | Adjust price or use Limit order |
0x3005 | PriceTooLow | Price is too low (must be at least 1 basis point) | Use price >= 1 bps |
0x3006 | PriceTooHigh | Price is too high (must be less than 10000 basis points) | Use price < 10000 bps |
0x3007 | SlippageExceeded | IOC fill would cross the supplied worst acceptable price | Loosen slippage or improve price |
0x3008 | InsufficientFill | IOC filled fewer units than min_fill_quantity required | Lower min fill or wait for more liquidity |
0x3009 | NoFillForIoc | IOC order matched no resting liquidity | Use Limit/PostOnly or wait for liquidity |
0x300A | SelfTradeAbort | Self-trade encountered while self-trade behavior is Abort | Cancel/modify own resting order first |
0x300B | PostOnlyModeActive | IOC submitted while protocol is in PostOnly mode | Submit Limit or PostOnly |
0x300C | OrderNotExpired | Reclaim target is not expired or flagged expired-claimable | Wait until the order is reclaimable |
0x300D | InsufficientBalance | Taker balance is below required collateral/shares | Fund the relevant token account |
0x300F | MaxTotalSharesExceeded | New paired issuance would exceed the market's per-side issuance cap | Reduce new issuance or update the cap |
0x3010 | AuthorityClaimNotEligible | Authority timelock has not elapsed | Wait until the eligible timestamp |
0x3011 | OrderbookCrossedPostInsert | Orderbook crossed after place-order mutation | Critical invariant violation; report as bug |
0x3012 | InsufficientFreeBalance | Free-funds balance below required amount | Ensure sufficient free-funds balance |
0x3013 | MinRestingNotionalNotMet | Resting order/remainder below configured notional floor | Increase size or use IOC |
0x3014 | OrderPriceOutOfBand | Maker price falls outside the allowed band around mid | Adjust price to within ±1000 bps of mid |
0x3015 | TraderLedgerFull | Trader ledger has reached maximum capacity | Evacuate an idle free-only slot to its owner, or settle/withdraw an existing position |
0x3016 | OrderbookNotEmpty | Cannot close market; orderbook still has resting orders | Cancel all orders before closing |
0x3017 | TraderLedgerNotAllocated | Trader ledger PDA not yet allocated | Run EnsureTraderLedgerSpace prelude first |
0x3018 | TraderLedgerOversized | Trader ledger account exceeds expected size | Report as bug |
0x3019 | OrderbookTreeCorruption | Deep orderbook tree links are internally inconsistent | Report as bug |
0x301A | InternalInvariantViolated | Internal order processing invariant was violated | Report as bug |
0x301B | BookConsistencyInvariantViolated | Orderbook slot counts or cached best prices are inconsistent after mutation | Critical invariant violation; report as bug |
0x301C | CrossedBookInvariantViolated | Orderbook has a matchable crossed bid/ask pair after mutation | Critical invariant violation; report as bug |
0x301D | UnsupportedAccountVersion | Recognized account type has an unsupported layout version | Upgrade the program/SDK or drain the old layout |
0x301E | PositionMarketMismatch | ForceClose position does not belong to the supplied market | Supply the position's canonical market |
0x301F | PositionAlreadySettled | ForceClose position is already settled | No ForceClose action remains |
0x3020 | ResidualShareLocks | ForceClose position retains ask-side share locks | Cancel or reclaim share-backed orders first |
0x3021 | NothingToForceClose | ForceClose has no collateral or economic order progress to release | Do not retry this position |
0x3022 | InvalidOrderTypeForInstruction | Supplied order type is unsupported by the selected instruction | Use the instruction matching the order type |
0x3023 | TraderLedgerCapacityUnsafe | Requested ledger is above 4,225 seats or lacks strict headroom over both book sides | Use an allowed tier with num_seats > bids_size + asks_size |
Order Error Examples#
// Handle insufficient balance
if (error.code === 0x300d) {
const required = calculateCollateral(price, quantity);
console.log(`Need ${required} USDT to place this order`);
// Prompt user to deposit
}
// Handle PostOnly rejection
if (error.code === 0x3004) {
console.log('Your PostOnly order would match immediately');
// Either adjust price or switch to Limit
}
// Handle order not found
if (error.code === 0x3003) {
console.log('Order not found - may have been filled');
// Refresh order book state
}
Math Errors (0x4001)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0x4001 | MathOverflow | Arithmetic overflow or underflow | Use smaller values or check inputs |
Math Error Example#
// This typically indicates a bug or extreme values
if (error.code === 0x4001) {
console.error('Math overflow detected - this should not happen');
console.error('Check your input values:', { price, quantity });
// Report as bug if values are reasonable
}
Account Errors (0x5001 - 0x500E)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0x5001 | InvalidAccountType | Account discriminator does not match expected type | Use correct account |
0x5002 | InvalidAccountOwner | Account owner is not the expected program | Verify account ownership |
0x5003 | InvalidPDA | PDA derivation does not match expected seeds | Check PDA derivation |
0x5004 | AlreadyInitialized | Account has already been initialized | Use existing account |
0x5005 | InsolvencyDetected | Point-of-payout vault-coverage failure: a concrete token debit or payout would leave the market vault unable to cover its recorded liabilities | Critical error — report as bug |
0x5006 | UnauthorizedInitializer | Initializer is not the program's upgrade authority | Use the correct authority |
0x5007 | DuplicateAccount | Two mutable accounts in the same instruction share the same address | Use distinct accounts |
0x5009 | FailedToSerializeEvent | Internal event recorder failed to serialize | Report as bug |
0x500A | FailedToFlushBuffer | Internal event recorder failed to flush buffer | Report as bug |
0x500B | InvalidRecorderPayloadLength | LOG payload length does not match declared count | Report as bug |
0x500C | InvalidRecorderVersion | LOG payload version is not recognized | Update client SDK |
0x500D | InvalidRecorderAuthorityKind | LOG payload authority kind is invalid | Report as bug |
0x500E | InvalidRecorderEventCount | LOG payload event count is out of range | Report as bug |
Account Error Examples#
// Handle PDA derivation errors
if (error.code === 0x5003) {
// Verify PDA derivation
const [expectedPda] = PublicKey.findProgramAddressSync(
[Buffer.from('seesaw'), Buffer.from('market'), marketIdBuffer],
programId
);
console.log('Expected PDA:', expectedPda.toString());
}
// Handle insolvency (critical)
if (error.code === 0x5005) {
console.error('CRITICAL: Insolvency detected - report as bug immediately');
// This indicates a protocol-level issue
}
Position Errors (0x6001)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0x6001 | ProtocolPaused | Protocol is paused | Wait for protocol to resume |
Position Error Example#
// Handle protocol pause
if (error.code === 0x6001) {
console.log('Protocol is currently paused');
// Check announcements for more info
}
Token Errors (0x7001 - 0x7007)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0x7001 | CannotExpire | Cannot expire market (not past expiration window or already resolved) | Wait for expiration window |
0x7002 | InvalidRedemption | Cannot redeem tokens that are not winning | Only winning shares pay out |
0x7003 | InvalidMint | Token account mint does not match expected mint | Use correct token mint |
0x7004 | SolvencyViolation | Custody-boundary solvency failure: a deposit/withdraw mutation would break the lifecycle-aware share-liability plus fee floor | Critical — report as bug |
0x7005 | SolvencyInvariantViolated | Post-mutation runtime invariant assertion: the solvency invariant was re-checked after a share or fee mutation and failed | Critical — report as bug |
0x7006 | InvalidSettlementMintDecimals | Settlement mint must use exactly 6 decimals | Use a 6-decimal SPL Token v1 mint |
0x7007 | CollateralMirrorInconsistent | Terminal redemption found an inverted collateral mirror without slot-share provenance | Report as state-consistency bug |
Solvency alarm: monitor 0x5005, 0x7004, AND 0x7005 together — all three
signal a solvency-invariant breach, differing only by which layer detected it.
Token Error Examples#
// Handle losing position redemption attempt
if (error.code === 0x7002) {
console.log('These shares did not win - payout is 0');
}
// Handle market expiration check
if (error.code === 0x7001) {
console.log('Market cannot be expired yet - check expiration window');
}
Fee, Referral, Spline, and Bounded-Operation Errors (0x8001 - 0x8026)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0x8001 | InvalidFeeCurve | Fee curve parameters out of bounds (cap or decay exceeds max) | Use valid fee curve parameters |
0x8002 | InvalidFeeSplit | Fee split shares do not sum to exactly 10,000 | Ensure splits sum to 10000 bps |
0x8003 | ReferrerAlreadySet | Referrer has already been set for this account | Cannot change referrer once set |
0x8004 | SelfReferralForbidden | Account cannot refer itself | Use a different referrer address |
0x8005 | ReferrerTreasuryMismatch | Referrer treasury PDA does not match expected derivation | Use correct treasury PDA |
0x8006 | AccumulatedAmountZero | Nothing to claim — accumulated amount is zero | Wait for earnings to accumulate |
0x8007 | FeeConfigRateLimit | Fee-governance update called within the shared rate-limit window | Wait for rate-limit window to expire |
0x8008 | TreasuryIndexOutOfRange | Treasury recipient index is >= MAX_TREASURY_RECIPIENTS (8) | Use an index in [0, 8) |
0x8009 | TreasuryRecipientMismatch | Provided treasury token account does not match stored recipient | Use the correct treasury token account |
0x800A | InvalidTreasuryRecipient | Treasury recipient address is invalid (uninitialized or wrong mint) | Use a valid, funded token account |
0x800B | DuplicateTreasuryRecipient | Two entries in the treasury recipient array share the same address | Use distinct token accounts |
0x800C | TreasuryUpdateRateLimit | UpdateTreasuryRecipients called within rate-limit window | Wait for rate-limit window to expire |
0x800D | OperationalParamsRateLimit | UpdateOperationalParams called within rate-limit window | Wait for rate-limit window to expire |
0x800E | MicrostructureRateLimit | Global tick/min or market-local cap update called within its cooldown | Wait for the applicable cooldown |
0x800F | ReferralCacheMismatch | Referral binding differs from or corrupts the immutable cache | Refresh canonical referral and position state |
0x8010 | InvalidReferralRollupBatch | Rollup batch shape, ordering, or common attribution is invalid | Rebuild a canonical sorted batch |
0x8011 | ReferralFeesPending | Terminal close is blocked by unswept referral liability | Roll up pending referral fees before closing |
0x8012 | ReferralLiabilityMismatch | Market and position referral liabilities do not reconcile | Stop and reconcile protocol state |
0x8013 | InvalidSplineConfig | Spline operational settings are invalid | Correct the spline configuration |
0x8014 | InstructionNotYetEnabled | Dormant or frozen instruction behavior is not enabled | Do not retry; wait for a separately reviewed protocol activation |
0x8015 | InvalidSplineShape | Spline levels are malformed or have no executable quote | Submit a valid bounded spline |
0x8016 | UnauthorizedSplineMaker | Caller is not the spline's recorded creator | Use the recorded creator signer |
0x8017 | StaleSequence | Spline update sequence did not strictly increase | Refresh state and use a newer sequence |
0x8018 | InvalidMidPrice | Spline midpoint is outside the executable range | Use a midpoint strictly between the price bounds |
0x8019 | InvalidSplineSeries | Spline and market feed/duration series do not match | Attach a spline for the canonical market series |
0x801A | InsufficientSplineCommitment | Spline collateral is below the configured exposure floor | Increase committed collateral |
0x801B | SplineGenerationMismatch | Signed quote targets a different program-owned shape generation | Read the current spline and rebuild the quote |
0x801C | InvalidSplineQuoteOrigin | Signed quote origin is negative, future-dated, or too old | Rebuild with the current Unix origin and submit within the configured age bound |
0x801D | MissingSplineAccounts | Required canonical creator spline account is absent or malformed | Supply the directly-derived creator spline account in the canonical trailing position. |
0x801E | ProtocolShareTooLow | Protocol fee share is below the 2,000-bps wash-cost floor | Increase the protocol share |
0x801F | MakerRebateShareTooHigh | Maker fee share exceeds the 4,000-bps cap | Lower the maker rebate share |
0x8020 | MakerRebateRestBoundTooHigh | Maker resting-age requirement exceeds one hour | Lower the resting-age requirement |
0x8021 | UnsettledSplines | Close is blocked by attached spline liability or occupancy | Close/detach and settle all splines |
0x8022 | OrderIdExhausted | Next insertion sequence cannot form an opaque order ID | Stop placement and migrate/recover the market |
0x8023 | UnsupportedFreeFundsSide | Free-funds cancellation encountered an ask-side share refund | Use the full-account cancellation route |
0x8024 | BulkCancelIncomplete | More orders qualify than the fixed atomic work bound | Cancel explicit IDs in batches of six |
0x8025 | RestingNotionalTooSmall | Partial reduction leaves a nonzero remainder below the floor | Cancel fully or leave a larger remainder |
0x8026 | SplineCommitmentUnderflow | A spline commitment decrement exceeded the recorded commitment | Stop and reconcile spline/market accounting |
Fee Error Examples#
// Handle fee split validation
if (error.code === 0x8002) {
console.log('Fee splits must sum to exactly 10000 bps');
}
// Handle already-set referrer
if (error.code === 0x8003) {
console.log('Referrer is already set and cannot be changed');
}
Authority, Oracle Governance, and Emergency Errors (0x9001 - 0x9008)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0x9001 | NoPendingAuthority | ClaimAuthority called but no authority rotation is pending | Initiate an authority rotation first |
0x9002 | UnauthorizedClaim | Signer does not match the pending authority address | Use the correct pending authority key |
0x9006 | EmergencyDelayNotElapsed | Force-cancel delay has not elapsed after entering force-cancel mode | Wait until the configured delay elapses |
0x9007 | UnauthorizedPauser | Signer is neither config authority nor configured nonzero pauser | Use the authority or configured pauser |
External-Market Errors (0xA001 - 0xA012)#
| Code | Name | Description | Resolution |
|---|---|---|---|
0xA001 | WrongResolver | Signer does not match the market resolver authority | Use the bound resolver |
0xA002 | ResolverNotRegistered | Resolver is absent from the registry | Register the resolver |
0xA003 | ResolverRevoked | Resolver is revoked | Use governance wind-down procedures |
0xA004 | MarketKindDisabled | Market kind is disabled globally or for the resolver | Enable the kind before opening |
0xA005 | UnsupportedMarketKind | Market kind or leg count is unsupported | Use binary with two legs |
0xA006 | MarketHalted | New order placement is blocked | Use an allowed exit operation |
0xA007 | ExternalMarketInvalid | External-market inputs, provenance, or OpenDisabled open attempt is invalid | Correct the request or use an existing market |
0xA008 | InvalidPayoutNumerators | Active numerators do not sum to 10,000 or the inactive suffix is nonzero | Supply a canonical payout vector |
0xA009 | MarketMetaMismatch | Market metadata belongs to another market | Supply the canonical metadata PDA |
0xA00A | ExternalMarketNotExpired | Permissionless expiry time has not elapsed | Retry after the expiry window |
0xA00B | PreallocationReceiptMismatch | Receipt commitment, market, resolver, creator, or arguments differ | Supply the canonical receipt and committed arguments |
0xA00C | PreallocationReceiptNotActive | Receipt has already been consumed or reclaimed | Do not replay the completed lifecycle action |
0xA00D | PreallocationReclaimTooEarly | Non-creator caller attempted reclaim before the permissionless boundary | Have the creator reclaim or wait for the boundary |
0xA00E | PreallocationTargetMismatch | Prepared capacity, seats, derived size, or child bounds differ | Use the frozen external-market allocation targets |
0xA00F | PreallocationDataNotZero | Prepared child account contains initialized or nonzero data | Supply a vacant or wholly zero canonical child account |
0xA010 | PreallocationMarketExists | A live market or metadata account blocks begin or reclaim | Use the existing market or a new external reference |
0xA011 | ExternalCloseTimeOutOfRange | External market close time is outside the supported finite horizon | Use a close time within the one-year horizon |
0xA012 | ExternalExpiryDeadlineOverflow | External market expiry deadline cannot be represented as i64 | Reduce the close time or expiry window |
Reclaim Integration Errors (0xB001 - 0xB025)#
The historical native-witness errors remain ABI-stable. The legacy bridge tags
are permanently frozen and return FrozenLegacyReclaim before payload parsing
or account access; the standalone verifier path uses its versioned error ABI.
| Code | Name | Description | Resolution |
|---|---|---|---|
0xB001 | ReclaimInvalidInstruction | Native Reclaim instruction is invalid | Rebuild the instruction from canonical inputs |
0xB003 | ReclaimInvalidAccountSize | Native Reclaim account size is invalid | Use the canonical account layout |
0xB005 | ReclaimInvalidPda | Native Reclaim PDA is invalid | Re-derive the canonical PDA |
0xB011 | ReclaimInvalidWitnessSet | Native Reclaim witness set is invalid | Use a valid witness quorum |
0xB018 | ReclaimInvalidClaimKind | Native Reclaim claim kind is invalid | Use a supported claim kind |
0xB019 | ReclaimInvalidProof | Native Reclaim proof is invalid | Obtain a valid witness proof |
0xB01D | ReclaimWrongWitnessEpoch | Native Reclaim witness epoch is invalid | Use the active witness epoch |
0xB01E | ReclaimThresholdNotMet | Retired/reserved; no live path emits this code | Do not retry based on this retired code |
0xB01F | ReclaimUnknownWitness | Retired/reserved; no live path emits this code | Do not retry based on this retired code |
0xB021 | ReclaimInvalidSignature | Native Reclaim signature is invalid | Obtain valid signatures |
0xB022 | ReclaimClaimBindingMismatch | Native Reclaim claim bindings do not match | Rebuild bindings from core state |
0xB023 | ReclaimInvalidTransition | Native Reclaim transition is invalid | Use a permitted transition |
0xB024 | ReclaimClaimAlreadyConsumed | Native Reclaim claim receipt was already consumed | Use a fresh claim identity |
0xB025 | FrozenLegacyReclaim | Legacy Reclaim bridge instruction is frozen | Use the standalone verifier V1 lifecycle |
The retired wire holes are ReclaimIdentifierMismatch (0xB01A),
ReclaimClaimStale (0xB01B), ReclaimClaimFromFuture (0xB01C), and
ReclaimDuplicateWitness (0xB020). They are historical names only and have no
corresponding live enum variants.
Error Handling Best Practices#
TypeScript Error Handler#
function handleSeesawError(error: any): string {
const code = error.code || error.error?.code;
const errorMessages: Record<number, string> = {
0x1001: 'Market already exists',
0x1002: 'Invalid market state for this operation',
0x1004: 'Trading has ended for this market',
0x2002: 'Oracle price is stale - try again shortly',
0x3001: 'Invalid order quantity',
0x300d: 'Insufficient balance for this order',
0x3004: 'PostOnly order would match - adjust price',
// Add more as needed
};
return errorMessages[code] || `Unknown error: ${code}`;
}
Retry Logic#
async function withRetry<T>(
fn: () => Promise<T>,
options: { maxRetries: number; retryableErrors: number[] }
): Promise<T> {
let lastError: any;
for (let i = 0; i < options.maxRetries; i++) {
try {
return await fn();
} catch (e: any) {
lastError = e;
if (!options.retryableErrors.includes(e.code)) {
throw e;
}
await sleep(1000 * Math.pow(2, i));
}
}
throw lastError;
}
// Use with oracle errors
await withRetry(() => snapshotPrice(market), {
maxRetries: 5,
retryableErrors: [0x2002], // StaleOracle
});
Error Code Quick Reference#
MARKET (0x10xx) ORACLE (0x20xx) ORDER (0x30xx)
├─ 0x1001 MarketExists ├─ 0x2001 OracleMismatch ├─ 0x3001 InvalidQuantity
├─ 0x1002 InvalidState ├─ 0x2002 StaleOracle ├─ 0x3002 OrderbookFull
├─ 0x1003 TradingNotStarted ├─ 0x2003 InvalidPrice ├─ 0x3003 OrderNotFound
├─ 0x1004 TradingEnded ├─ 0x2004 ConfidenceTooWide ├─ 0x3004 WouldCross
├─ 0x1005 AlreadyResolved ├─ 0x2005 FeedIdMismatch ├─ 0x3005 PriceTooLow
├─ 0x1006 MarketNotResolved ├─ 0x2006 InvalidOracleData ├─ 0x3006 PriceTooHigh
├─ 0x1007 TooEarly └─ 0x2007 OraclePriceJump ├─ 0x3007 SlippageExceeded
├─ 0x1008 EpochNotStarted ├─ 0x3008 InsufficientFill
├─ 0x1009 EpochNotEnded MATH (0x40xx) ├─ 0x3009 NoFillForIoc
├─ 0x100A NotOwner └─ 0x4001 MathOverflow ├─ 0x300A SelfTradeAbort
├─ 0x100B PositionsRemaining ├─ 0x300B PostOnlyModeActive
├─ 0x100C MarketCloseTimeout ACCOUNT (0x50xx) ├─ 0x300C OrderNotExpired
├─ 0x100D InvalidCreator ├─ 0x5001 InvalidAccountType ├─ 0x300D InsufficientBalance
├─ 0x100E VaultNotEmpty ├─ 0x5002 InvalidAccountOwner├─ 0x300F MaxTotalSharesExceeded
├─ 0x100F InvalidDuration ├─ 0x5003 InvalidPDA ├─ 0x3010 AuthorityClaimNotEligible
├─ 0x1010 InvalidConfidenceRatio├─ 0x5004 AlreadyInitialized├─ 0x3011 OrderbookCrossedPostInsert
└─ 0x1011 InvalidStateTransition├─ 0x5005 InsolvencyDetected├─ 0x3012 InsufficientFreeBalance
├─ 0x5006 UnauthorizedInitializer├─ 0x3013 MinRestingNotionalNotMet
POSITION (0x60xx) ├─ 0x5007 DuplicateAccount ├─ 0x3014 OrderPriceOutOfBand
└─ 0x6001 ProtocolPaused ├─ 0x5009 FailedToSerializeEvent├─ 0x3015 TraderLedgerFull
├─ 0x500A FailedToFlushBuffer├─ 0x3016 OrderbookNotEmpty
TOKEN (0x70xx) ├─ 0x500B InvalidRecorderPayloadLength├─ 0x3017 TraderLedgerNotAllocated
├─ 0x7001 CannotExpire ├─ 0x500C InvalidRecorderVersion├─ 0x3018 TraderLedgerOversized
├─ 0x7002 InvalidRedemption ├─ 0x500D InvalidRecorderAuthorityKind├─ 0x3019 OrderbookTreeCorruption
├─ 0x7003 InvalidMint └─ 0x500E InvalidRecorderEventCount├─ 0x301A InternalInvariantViolated
├─ 0x7004 SolvencyViolation ├─ 0x301B BookConsistencyInvariantViolated
├─ 0x7005 SolvencyInvariantViolated └─ 0x301C CrossedBookInvariantViolated
└─ 0x7006 InvalidSettlementMintDecimals
FEE/REFERRAL/TREASURY (0x80xx) AUTHORITY/GOVERNANCE/EMERGENCY (0x90xx)
├─ 0x8001 InvalidFeeCurve ├─ 0x9001 NoPendingAuthority
├─ 0x8002 InvalidFeeSplit ├─ 0x9002 UnauthorizedClaim
├─ 0x8003 ReferrerAlreadySet ├─ 0x9003 NoPendingOracleUpdate
├─ 0x8004 SelfReferralForbidden ├─ 0x9004 OracleTimelockNotElapsed
├─ 0x8005 ReferrerTreasuryMismatch ├─ 0x9006 EmergencyDelayNotElapsed
├─ 0x8006 AccumulatedAmountZero ├─ 0x9007 UnauthorizedPauser
├─ 0x8007 FeeConfigRateLimit └─ 0x9008 OracleProgramIdFrozen
├─ 0x8008 TreasuryIndexOutOfRange
├─ 0x8009 TreasuryRecipientMismatch
├─ 0x800A InvalidTreasuryRecipient
├─ 0x800B DuplicateTreasuryRecipient
├─ 0x800C TreasuryUpdateRateLimit
├─ 0x800D OperationalParamsRateLimit
├─ 0x800E MicrostructureRateLimit
├─ 0x800F ReferralCacheMismatch
├─ 0x8010 InvalidReferralRollupBatch
├─ 0x8011 ReferralFeesPending
├─ 0x8012 ReferralLiabilityMismatch
├─ 0x8013 InvalidSplineConfig
├─ 0x8014 InstructionNotYetEnabled
├─ 0x8015 InvalidSplineShape
├─ 0x8016 UnauthorizedSplineMaker
├─ 0x8017 StaleSequence
├─ 0x8018 InvalidMidPrice
├─ 0x8019 InvalidSplineSeries
├─ 0x801A InsufficientSplineCommitment
├─ 0x801B SplineGenerationMismatch
├─ 0x801C InvalidSplineQuoteOrigin
├─ 0x801D MissingSplineAccounts
├─ 0x801E ProtocolShareTooLow
├─ 0x801F MakerRebateShareTooHigh
├─ 0x8020 MakerRebateRestBoundTooHigh
├─ 0x8021 UnsettledSplines
├─ 0x8022 OrderIdExhausted
├─ 0x8023 UnsupportedFreeFundsSide
├─ 0x8024 BulkCancelIncomplete
├─ 0x8025 RestingNotionalTooSmall
└─ 0x8026 SplineCommitmentUnderflow
`OracleProgramIdFrozen (0x9008)`, along with the related oracle-timelock
entries, is retained as an append-only legacy error identity. The historical
`0x31`/`0x32` instruction assignments are reserved wire holes; current default
dispatch rejects them with `InvalidInstructionData` before any error variant is
constructed.
EXTERNAL MARKET (0xA0xx)
├─ 0xA001 WrongResolver
├─ 0xA002 ResolverNotRegistered
├─ 0xA003 ResolverRevoked
├─ 0xA004 MarketKindDisabled
├─ 0xA005 UnsupportedMarketKind
├─ 0xA006 MarketHalted
├─ 0xA007 ExternalMarketInvalid
├─ 0xA008 InvalidPayoutNumerators
├─ 0xA009 MarketMetaMismatch
├─ 0xA00A ExternalMarketNotExpired
├─ 0xA00B PreallocationReceiptMismatch
├─ 0xA00C PreallocationReceiptNotActive
├─ 0xA00D PreallocationReclaimTooEarly
├─ 0xA00E PreallocationTargetMismatch
├─ 0xA00F PreallocationDataNotZero
├─ 0xA010 PreallocationMarketExists
├─ 0xA011 ExternalCloseTimeOutOfRange
└─ 0xA012 ExternalExpiryDeadlineOverflow