Skip to main content
Every fallible entrypoint fails by panicking with a numeric contract error. Soroban surfaces that number to the caller (Error(Contract, #<code>) in the RPC response), so the code is all an integrator gets back — there is no message. Codes are stable: they are explicit discriminants and are never renumbered, so gaps in the sequence are expected and deliberate. Match numeric codes, not variant display text.

Groups

Generic errors

Codes 1 (AssetNotSupported), 3 (InvalidTicker), 11 (InvalidExchangeSrc), and 12 (PairNotActive) are declared but never constructed in contract code. They are reserved so existing codes never shift; a deployed contract will not surface them.

Collateral and pool errors

Code 110 (PositionNotFound) is reserved and never constructed by a contract.
Self-liquidation of an account is allowed. liquidate is fully permissionless, including by the account owner. #133 fires only when SeizeMode::Credit(id) names the liquidated account itself, which would hand its own collateral straight back.

Spoke errors

Oracle errors

Price failures reach users indirectly: price-aggregator prices and price_spread panic on an unusable price, and so does every controller entrypoint that values an account. quotes never panics — it returns a PriceStatus with valid: false instead.

Flash loan and strategy errors

DeFindex strategy adapter errors

The reference vault adapter uses its own enum, independent of the codes above.

Integration handling

  • Treat oracle errors as retryable only after source recovery or configuration change. See the oracle disruption runbook.
  • Treat cap, liquidity, and utilization errors (#112, #127, #311, #312) as amount/headroom problems.
  • Treat auth and spoke-listing errors as request-construction problems.
  • Treat the five *RoundsToZeroShares codes as “amount too small for this market’s current index” — increase the amount.
  • Use controller views to preflight, but treat mutation results as authoritative.