Errors and failure handling
Decode program errors from the IDL and handle the failures integrators meet most often.
Updated Nov 9, 2026
A failed simulation returns something like {"InstructionError":[0,{"Custom":6034}]}. Both programs ship their error table in the IDL, so the mapping from a code to a name and message should be derived, never transcribed. The complete tables are in the errors reference.
Decoding
import { IDL, leverageDelegateIdl } from "@omnipair/dusk-sdk"
type IdlError = { code: number; name: string; msg?: string }
function table(idl: unknown) {
const errors = (idl as { errors?: IdlError[] }).errors ?? []
return new Map(errors.map((entry) => [entry.code, entry]))
}
const DUSK = table(IDL)
const DELEGATE = table(leverageDelegateIdl())
export function describe(code: number) {
const entry = DUSK.get(code) ?? DELEGATE.get(code)
return entry ? `${entry.msg ?? entry.name} (${entry.name})` : null
}Dusk codes start at 6000 and the delegate's at 6000 too, so decide which program failed from the instruction index before looking the code up; the app checks the Dusk table first only because most transactions target it.
Failures you will meet
| Error | Why | What to do |
|---|---|---|
SlippageExceeded | The market moved past the minimum output you sent | Re-quote and retry; do not loosen tolerance blindly |
InsufficientCashReserve0 / …1, InsufficientLiquidity | Only cash can leave; that side is lent out | Smaller size, or wait for repayments |
BorrowingPowerExceeded | The borrow exceeds the buffered borrow limit | Re-run the capacity preview and borrow within maxBorrowAmount |
DailyLimitExceeded | The asset's 24-hour public borrow bucket is spent | Borrow less or wait for the bucket to refill |
InsufficientMarketHealth, InsufficientBorrowHeadroom | The action would breach the market's health floor or an hLP vault's funding headroom | Reduce size; check previewHlpDepositCapacity |
ReduceOnlyMode, MarketReduceOnly, ReduceOnlyHasDebt | The protocol or market is in reduce-only, or a reduce-only withdrawal would leave debt | Only repayments and exits are allowed |
MarketNotStarted, InstructionNotLive | The market's trading start is in the future, or the instruction is gated during launch | Wait for the start time |
LaunchRateLimitSplitTransaction | Two swap-like actions on one market in one transaction while the launch limiter is on | Send them separately |
Undercollateralized, NotUndercollateralized, PositionNotLiquidatable | The position is not in the state the instruction requires | Re-read the position and refresh the liquidation preview |
LiquidationRepayTooLarge | A fill exceeds the program's permitted partial or full amount | Use the program-previewed repayment |
LeverageMultiplierTooHigh, LeverageInitialMarginTooLow | The position breaks the absolute multiplier or its stored/admission margin terms | Lower the multiplier or size, or add margin |
LeveragePositionNotLiquidatable | Health has not failed | Nothing to do |
HlpSettlementUnavailable, HlpNotLiquidatable | The vault's settlement reference diverged, or it is not exhausted | Wait for a settlement, or nothing to do |
UtilizationGuardExceeded, ProposalTimelockNotReady, ProposalExecutionWindowExpired, ProposalStale | Operator-bundle timing, current-state commitments or utilization guards | Wait, or re-propose if stale |
InvalidSigner | A harvest by someone who is neither owner, recipient nor harvest authority | Sign with an allowed key |
UnsupportedAssetDecimals | A mint with more than nine decimals | Unsupported |
InvalidTokenProgram, InvalidTokenAccount | Wrong token program for the mint, or an account that is not the canonical ATA | Derive with the mint's own program |
Delegate TriggerNotMet, InvalidOrder | The order's condition is not met, or it no longer matches the position | Typed skip; re-read and re-evaluate |
Failures that are not program errors
- Blockhash expired. Rebuild after re-reading state; never re-sign a transaction whose result is unknown.
- Account not found or wrong discriminator. Your client and the deployment disagree; check the pin on Addresses.
- Preview or capacity returned, transaction failed. Previews skip permission, reduce-only, token-account, referral, slippage and freshness checks. Simulate the real transaction.
- Indexer 409 or 503. Identity mismatch or freshness not met; see read API and streams. Never fall back to a different deployment.
Expected races
Anything that depends on someone else's state can lose a race: an order already executed, a liquidation already filled, a position already repaid, an operator bundle already executed or replaced. Treat these as typed skips rather than failures, re-read the accounts, and re-evaluate. The keeper operations page has the full list.