Skip to content
Logo

Errors

Failures come from two places:

  • The API returns a standard gRPC status — a code plus a human-readable message. The SDKs surface it verbatim.
  • The margin program rejects a transaction with a custom program error code (custom program error: 0x…). You see these from Solana RPC, from SponsorshipService.SponsorTransaction, or in TxService.SubscribeTxStatus failure events.

Generated unary service calls need an explicit retry policy. Managed SDK components retry selected failures: authentication can refresh a session, streams can reconnect, and QuotingCore can resend the same signed transaction. See Rust SDK. Do not build a replacement transaction merely because a submission timed out.

gRPC status codes

gRPC codeWhenRetry?
INVALID_ARGUMENTA required id is missing (trader_id is required, perp_id is required), a list is too long (at most 100 ids, book depth ≤ 100), a bad page token or time range, an unsupported candle interval, a malformed or under-signed transaction.No — fix the request.
NOT_FOUNDUnknown trader account, perp, or collateral market.No.
UNAUTHENTICATEDMissing, malformed, expired, or revoked session token. On Authenticate: no outstanding nonce, a bad signature, or a key that controls no trader account.Re-run the auth handshake once, then retry.
PERMISSION_DENIEDValid session but wrong scope: the requested trader_id isn't controlled by the key, the session key isn't a required signer of a SubmitTx transaction, an organization without perps access, a trader with no organization calling GetSdkCredentials or PageTheTeam, or a RenameAccount signer that doesn't control the account.No.
RESOURCE_EXHAUSTEDRate limit hit, the server is at capacity, a simulation pool is busy, the transaction queue is full, or the sponsor refused for capacity. Also ends SubscribeAccountsAtRisk when the client falls behind.Yes, with exponential backoff.
FAILED_PRECONDITIONA user or maker history RPC (GetActivity, GetAccountHistory, GetInterestHistory, GetFills, ListRecentQuotes, …) on a deployment without the history archive, or a risk view whose backing feature isn't enabled.No — the feature isn't available on this deployment.
UNAVAILABLETransport drop; the node is restarting; margin state hasn't loaded or is stale; sponsorship or simulation isn't configured; an upstream read failed.Yes, with backoff.
DATA_LOSSA live stream (SubscribeActivity, SubscribeFills, SubscribeCandles) fell behind the server's buffer and was closed.Reconnect, then reconcile with the matching unary RPC.
DEADLINE_EXCEEDEDYour deadline, or the server's own request deadline, elapsed.Yes, for idempotent reads.
UNIMPLEMENTEDThe RPC is declared in the schema but not served yet (see the API overview), or an unsupported option such as mark/index candles.No.
INTERNALA server bug.Capped retry (1–3 attempts), then report it.

The message string is for humans and may change; branch on the code.

Session-specific failures

Margin maker sessions last 6 hours and challenge nonces 30 seconds. AuthFlow in both SDKs refreshes ahead of expiry and runs Challenge → sign → Authenticate from scratch, so nonce expiry is not your concern. Sessions are not guaranteed to survive a server restart or a move to another node, though: a previously good token can start returning UNAUTHENTICATED. Treat that as a cue to re-authenticate once with auth.refresh() — on the AuthFlow in either SDK. The Rust maker Client's managed streams and session heartbeat already do this on UNAUTHENTICATED.

Reading errors

use tonic::Code;
 
match account.get_account(req).await {
    Ok(res) => { /* ... */ }
    Err(status) => match status.code() {
        Code::ResourceExhausted | Code::Unavailable => backoff_and_retry().await,
        Code::NotFound => { /* no such trader account */ }
        _ => return Err(status.into()),
    },
}

In Rust, generated service clients return tonic::Status; the SDK's own helpers (Client::connect, AuthFlow) return flint_client_core::CoreError, re-exported as each crate's Error. In TypeScript, every failure is a GrpcError with a numeric code; asGrpcError, statusCode, statusMessage, and responseMetadata narrow an unknown error safely.

Transaction outcomes

TxService.SubmitTx returns once the server has accepted the transaction — not when it lands. Follow it on SubscribeTxStatus:

EventMeaning
ackAccepted for submission. Not confirmation.
landedObserved at processed commitment with no error.
failedReverted after landing, or timed out before landing. reason carries the cause, including program errors.

Save the signature before dispatch. Require RPC status at confirmed or finalized commitment with err: null before reporting success. If the outcome is unknown, follow transaction recovery.

SponsorshipService.SponsorTransaction waits for confirmation and returns the signature; a transaction the sponsor won't sign or that fails comes back as INVALID_ARGUMENT with the reason.

Program error codes

The margin program's custom errors, as numbered in the IDL (decimal / hex). The program also logs the failing source location and, for some codes, the subject (trader, asset, or perp id) — read the transaction logs for the detail the code alone can't carry.

Both on-chain clients ship the enum: FlintError in flint_margin_onchain::errors (Rust, FromPrimitive), and FLINT_ERROR__* constants with isFlintError(...) / getFlintErrorMessage(...) in @superis-labs/flint-idl.

General

CodeNameMeaning
1 / 0x1MathErrorArithmetic overflow, underflow, or division by zero inside the program. Usually an extreme amount.
2 / 0x2GenericA rejection whose reason is only in the program log. Read the logs.
8 / 0x8InvalidClockThe program couldn't read a usable clock.
15 / 0xFOperationDisabledThe operation is paused for this market or globally. The log names the operation.
23 / 0x17UnsupportedMintExtensionThe mint uses a Token-2022 extension outside the allowlist.
62 / 0x3EPositionDoesntExistA balance move on an asset the account holds no position in.

Margin and collateral

CodeNameMeaning
3 / 0x3HealthCheckFailedAn account touched by the instruction would fail its margin requirement afterwards. For a perp order this can be the taker or one of the makers; the log names the trader id.
6 / 0x6UtilisationThrottledThe pool's utilisation is at or above the throttle for this borrow or redeem.
7 / 0x7UtilisationOverflowThe action would leave the pool with borrows ≥ deposits.
11 / 0xBRedeemBelowMinimumThe redeem returned less than the caller's minimum.
12 / 0xCDepositLimitExceededThe market's deposit cap would be exceeded.
13 / 0xDBorrowLimitExceededThe market's borrow cap would be exceeded.
14 / 0xEFlowCapExceededThe market's net-flow limiter would be exceeded for this window.
28 / 0x1CSpotPositionLimitExceededThe account would hold more collateral positions than allowed.
48 / 0x30MarketBankruptThe market's borrow/lend pool is bankrupt (deposit price is zero).
63 / 0x3FInsufficientIsolatedDepositA withdraw or lend larger than the position's idle (unlent) balance.
64 / 0x40InsufficientDepositToRepayA repay larger than the position's idle balance plus its own lent deposit.
78 / 0x4ESpotProductNotCachedThe asset isn't in the program's product cache yet; a keeper sync must list it first.
87 / 0x57AccountLeverageExceededInitial margin clears, but the account's own leverage cap (setAccountLeverageCap) does not.

GetActionLimits and SimulateAction predict most of these before you sign — the limit's constraint names which one binds.

Perp orders

CodeNameMeaning
50 / 0x32PerpOrderLotsExceedPositionWidthThe order's lot count is too large for a position (it must fit in a signed 32-bit integer).
51 / 0x33PerpOrderAverageBeyondLimitThe average-price bound is worse than the single-fill limit: above it for a buy, or below it for a sell.
52 / 0x34PerpOrderFilledBelowMinimumThe order filled less than its min_fill_lots.
53 / 0x35PerpOrderUnfilledAn immediate-or-cancel order crossed nothing inside its limit.
54 / 0x36LinearPerpPositionLimitExceededThe account would hold more perp positions than allowed.
55 / 0x37LinearPerpOpenInterestCapExceededThe fill would push the contract past its open-interest cap.
56 / 0x38LinearPerpMarkExpiredThe contract's cached mark is past its validity window; retry after the next cache sync.
57 / 0x39PerpOrderNothingToReduceA reduce-only order on a perp the taker is flat on, or already holds in the order's direction.
58 / 0x3APerpOrderReducibleBelowMinimumA reduce-only order whose position is smaller than its minimum fill.
76 / 0x4CPerpOrderSelfMatchThe taker passed itself as a maker.
77 / 0x4DPerpOrderMakersUnorderedMaker accounts must be passed strictly ascending by trader id, without repeats.
79 / 0x4FLinearPerpNotCachedThe contract isn't in the program's perp cache yet.
88 / 0x58PerpOrderWouldCrossA post-only order would cross the makers passed in.
89 / 0x59PerpOrderNotFoundNo resting order of the trader's at that side and price.
90 / 0x5APerpOpenOrderLimitExceededThe trader is at the ceiling on resting orders on this contract.
91 / 0x5BLinearPerpPositionSizeExceededThe position would pass its size cap, counting resting orders as filled.
92 / 0x5CPerpOrderExpiredA Gtd expiry, or a modified resting-order expiry, is at or before the current slot.
94 / 0x5EPerpOrderMinimumUnreachableThe Ioc kind's min_fill_lots exceeds the order's lots.

OrderService.PreviewOrder simulates an order against the current book and margin before you sign it.

Order-book upkeep

The permissionless prunePerpOrders and forceCancelPerpOrders instructions, usually run by keepers.

CodeNameMeaning
93 / 0x5DPerpNothingToPruneNo dead order among the traders passed to prunePerpOrders.
95 / 0x5FPerpForceCancelMarginMetforceCancelPerpOrders on a trader that meets initial margin.
96 / 0x60PerpForceCancelNothingReservedforceCancelPerpOrders on a book whose orders reserve no margin.

PnL and funding settlement

CodeNameMeaning
59 / 0x3BNoRealisedPnlToSettleNothing is pending on the position.
60 / 0x3CPnlSettlePoolExhaustedA gain to settle, but the pool holds less than one tick.
61 / 0x3DLinearPerpPnlCurrencyMismatchThe market passed isn't the contract's PnL currency.
75 / 0x4BSettlementExceedsPendingTicksThe settlement exceeds, or points the other way from, what's pending.
80 / 0x50SettlementBelowMinimumLess is settleable than the caller's min_settle_ticks.

Liquidation, backstop, and loss socialization

Mostly relevant to keepers.

CodeNameMeaning
4 / 0x4HealthyAccountCantBeLiquidatedThe account meets maintenance margin.
5 / 0x5LiquidationDidNotDecreaseDeficitThe liquidation wouldn't improve the account's margin deficit.
16 / 0x10LiquidationCapLeavesDustBorrowThe capped repay would leave a dust-sized borrow.
17 / 0x11SelfPositionTransferLiquidator and liquidatee are the same account.
18 / 0x12AccountNotDistressedLoss socialization on an account that isn't distressed.
65 / 0x41NoDebtToSocializeThe account has no debt in that asset.
66 / 0x42SocializedAccountHoldsCollateralThe account still holds collateral above the dust line.
67 / 0x43LiquidationPairMismatchThe debt or collateral asset passed differs from the plan.
68 / 0x44LiquidationTransferredNothingThe liquidation would move nothing.
69 / 0x45LiquidationExchangeUnfairThe liquidatee would give up more value than the bonus allows.
70 / 0x46LiquidationCollateralBelowMinimumCollateral received is below the liquidator's min_collateral_received.
71 / 0x47LiquidationDebtAboveMaximumDebt taken on exceeds the liquidator's max_borrow_transfer.
72 / 0x48BackstopGivesDebtThe backstop would leave the liquidatee owing more.
73 / 0x49BackstopAssetNotHeldThe backstop names an asset the liquidatee holds no position in.
74 / 0x4ABackstopExchangeUnfairThe backstopper takes more value than it gives at fair prices.
82 / 0x52PerpLiquidationNothingToCloseThe liquidatee has no position on the contract.
83 / 0x53PerpLiquidationMakersIncompleteAn enabled quoting slot wasn't passed as a remaining account.
84 / 0x54BackstopPerpNotHeldThe backstop names a perp the liquidatee doesn't hold.
85 / 0x55BackstopTakeNothingA backstop with a zero percent.
86 / 0x56BackstopLeftoverBelowMinimumA partial backstop would leave the liquidatee under $500 of equity.

Delegates and passkeys

CodeNameMeaning
29 / 0x1DInvalidDelegateScopeAn empty delegate grant (reserved to mean revoked).
30 / 0x1ESecp256r1InstructionMalformedThe secp256r1 verification instruction is malformed.
31 / 0x1FPasskeyNotTopLevelA passkey-authorized instruction must be top level, not a CPI.
32 / 0x20PasskeyPrecompileMissingThe secp256r1 verification instruction must immediately precede the order.
33 / 0x21PasskeyIntrospectionFailedThe program couldn't read the instructions sysvar.
34 / 0x22PasskeyTooManyAccountsThe passkey intent binds more accounts than allowed.
35 / 0x23PasskeyCredentialMismatchThe assertion's credential isn't the delegate's.
36 / 0x24PasskeyRpIdMismatchThe relying-party id doesn't match the registered one.
37 / 0x25PasskeyUserNotVerifiedThe authenticator didn't report user verification.
38 / 0x26PasskeyClientDataMismatchclientDataJSON doesn't hash to what the authenticator signed, or doesn't carry the expected type, challenge, or origin.
39 / 0x27PasskeyIntentExpiredThe signed intent's validity window has passed.
40 / 0x28PasskeyIntentLifetimeTooLongThe signed intent's validity window is too long.
41 / 0x29PasskeyNonceMismatchThe intent's nonce isn't the delegate's next nonce.
42 / 0x2APasskeyNotAuthorizedThe delegate isn't a passkey, or its TRADE grant is revoked or expired.
43 / 0x2BPasskeyCredentialInvalidThe passkey credential is malformed (credential id or origin length out of bounds).
44 / 0x2CUnknownDelegateCredentialThe delegate credential's tag names no known kind.
45 / 0x2DPasskeyDomainInvalidThe configured challenge domain is empty or not printable ASCII.

Admin, keeper, and protocol operations

You won't see these from trading or quoting flows.

CodeNameMeaning
9 / 0x9FlashloanDisabledFlash loans are disabled.
10 / 0xAIllegalFlashloanThe flash-loan start/end pair is malformed.
19 / 0x13InvalidFeeDestinationFee collection to an account other than the configured destination.
20 / 0x14NothingToCollectNo fees to collect.
21 / 0x15UpdateNotYetEffectiveA proposed market update applied before its delay elapsed.
22 / 0x16UpdateExpiredA proposed market update applied after it expired.
24 / 0x18VaultAlreadyInitializedThe market vault already exists.
25 / 0x19SharePoolNotEmptyA share pool reset while it still holds shares.
26 / 0x1ALendingRateFeeTooHighThe lending-rate fee is out of range.
27 / 0x1BTargetUtilisationOutOfRangeThe target utilisation is out of range.
46 / 0x2EOracleIngestConfigurationInvalid oracle ingest configuration.
47 / 0x2FOracleTierConfigurationInvalid oracle tier configuration.
49 / 0x31OracleRevisionAlreadyPublishedThat oracle revision was already published.
81 / 0x51FeeCollectionBelowMinimumLess pool-backed fee accrual than the caller's min_collect_ticks.