Skip to the content
TAPEHOUSE

SDKs

Errors

Decode a revert from any Tapehouse contract into a named error with arguments, and look up what each custom error means and how to fix it.

Every contract reverts with a named custom error that carries the values behind the refusal. Each SDK decodes the revert data of the contracts, the baskets, the band, the Stock Tokens and USDG into that name and its arguments, and also decodes Solidity's Error(string) and Panic(uint256).

Decode a revert#

TypeScript
import { accounts, CROSS, decodeRevert } from '@tapehouse/sdk'

try {
  await client.simulateContract({
    ...accounts.borrow(deployments, { position: CROSS, assets: 500_000_000n, account, receiver: account }),
    account,
  })
} catch (error) {
  const revert = decodeRevert(error)
  if (revert?.errorName === 'InsufficientMargin') {
    const [equity, requirement] = revert.args
  }
  throw error
}

decodeRevert(error) takes the error viem throws from simulateContract, writeContract or readContract and returns { errorName, args }, or undefined if the revert is not one of the contracts'. decodeRevertData(data) does the same for raw revert data, and errorsAbi is the list of every error the SDK knows, as a viem ABI.

The error list the SDKs decode comes from the ABIs of ShortPositions, GapCover, MarginAccounts, Liquidator, GapBackstop, ReopeningAuction, StockLendingVault, SupplyVault, Basket, BandFeed, MorphoBandOracle, the band, the Stock Tokens and USDG. The Go SDK also decodes the margin engine's and the round feeds' errors. A selector that two contracts share decodes once, under the same name.

The sponsor paymaster's own errors (FreeOperationsUsed, SponsorshipPaused, PaymasterUnauthorized) are in none of the SDKs' lists. The RedStone round feed's (InvalidPayload, NotNewer and the rest of its payload checks) and the margin engine's (UpdateTooSoon, InvalidVolatility and others) are in the Go SDK's only. An error outside an SDK's list comes back undecoded, as raw data.

Errors that many contracts share#

These appear in several contracts with the same meaning.

ErrorMeaningFix
AssetHalted(symbol)The asset's band is haltedWait for the halt to lift. The band says who can halt
CorporateActionPending(symbol)The Stock Token has a multiplier change pendingWait until it is confirmed
SequencerNotSettled()The L2 sequencer is down or came back within the hourRetry after an hour of uptime
SessionUnknown()The band cannot tell whether the session is openRetry later
LiquidityUnknown(symbol)The engine could not read the asset's liquidityRetry later; the engine reads the asset's Uniswap pool
ZeroAmount()An amount of zeroPass a positive amount
Unauthorized(caller, account)The caller may not act for the accountThe owner calls setAuthorization(caller, true) first
Blocked(account)The issuer has blocklisted the accountNothing on Tapehouse's side lifts it
BorrowingIsPaused()The guardian paused new borrowingWait until the guardian lifts the pause
InsufficientMargin(equity, requirement)The position's equity is below its requirement, both USD with 18 decimalsBorrow less, deposit more collateral, or read liquidationPrice first
WeekendLeverageExceeded(gross, equity)Exposure passes equity times the weekend leverage cap, from the regular open before a closure until the reopeningReduce exposure or add equity
OwnershipCannotBeRenounced()Owner-only: the contract needs its ownerNot a caller error

Contracts that inherit OpenZeppelin also revert with its standard errors: OwnableUnauthorizedAccount(account), OwnableInvalidOwner(owner), ERC20InsufficientBalance, ERC20InsufficientAllowance, the other ERC20Invalid* errors, SafeERC20FailedOperation(token) and the SafeCast* overflow errors. The vaults' ERC4626ExceededMaxDeposit, ERC4626ExceededMaxMint, ERC4626ExceededMaxWithdraw and ERC4626ExceededMaxRedeem (receiver or owner, amount, max) mean the amount is above what the vault allows now: read maxDeposit, maxWithdraw or maxRedeem and ask for at most that.

MarginAccounts#

ErrorMeaningFix
UnknownPosition(position)The position is neither CROSS nor an asset with a Stock TokenUse an entry of accounts.positions
UnknownAsset(symbol)The symbol is not one of the engine's assetsCheck the symbol
UnsupportedToken(token, position)The token is not collateral here, or not in this positionDeposit it in the position the engine allows
AssetInOtherPosition(symbol, position)The account holds the asset in another position alreadyUse that position, or empty it first
InsufficientCollateral(token, amount)The position holds less than amount of the tokenAsk for less
BorrowingAgainstUsdg()A position holding USDG does not borrow USDGRepay with it instead
AssetRecovering(symbol, until)The band was seen halted or with a multiplier change pending less than the recovery window agoNo new risk against the asset until until (Unix seconds). accounts.recovery reads it
AssetFrozen(symbol)The issuer paused the Stock Token or blocklisted the accounts, so it cannot be seizedNo new loan or withdrawal in debt against it
AssetWrittenOff(symbol)Every unit the accounts held was burnedThe asset takes no deposit
HoldingNotEmpty(symbol)The holding in the position is still worth a raw unit or moreNot a caller error
AssetCapExceeded(symbol, cap)The accounts would hold more than the asset's capDeposit less; accounts.holding reads the cap
DebtCapExceeded(debt, cap)The positions together would owe more than the debt capBorrow less; accounts.limits reads the cap
WeekendDebtCapExceeded(debt, cap)The same across a closureBorrow less before a closure
Mandate*: MandateExpired(account, agent, expiresAt), MandateDebtLimit(debt, maxDebt), MandateLeverageLimit(leverage, maxLeverage), MandateReceiver(receiver, account)An agent acted outside its mandateStay within the debt and leverage limits, before the end time, and send to the account itself. accounts.mandateStatus says which stops it
InvalidMandate()A mandate must end in the future and allow leverage of at least 10,000 basis pointsFix the arguments of setMandate
NoLending(symbol), InvalidLending()The asset has no lending vault, or it does not lend this token to the accountsDo not lend that asset
OutOfReach(symbol, amount, reachable)The vault can return only reachable nowunlend at most reachable, or recall the rest
TooManyRecalls(symbol)The position has the maximum open recalls of the assetWait for one to settle, then settle
RecallTooSmall(amount)The recall is under the minimum and is not the first and whole oneRecall more
NothingToSettle()Nothing the position recalled is back yetWait
InvalidBasket(basket), BasketAlreadyAdded(basket), TooManyBaskets()The basket is not accepted, is accepted already, or the accounts take the maximumOwner-side
BasketFrozen(basket)The issuer paused one of the basket's tokens or blocklisted the accounts or the basketIts shares back no new loan or withdrawal in debt
TooManyAssets(count)The engine has more assets than the accounts take (eight)Owner-side
LengthMismatch(), InvalidDebtCaps(), InvalidPremium(), InsufficientReserve(reserve), InvalidReceiver()Owner-side arguments out of rangeNot a caller error
NotLiquidator(caller), NotBackstop(caller), NotGuardian(caller), PositionNotEmpty()A call reserved for the liquidator, the backstop or the guardian, or a write-off of a position that still holds collateralNot a caller error
LiquidatorAlreadySet, InvalidLiquidator, BackstopAlreadySet, InvalidBackstop, LendingAlreadySet, BandMismatchSet-once wiringNot a caller error

ShortPositions#

Besides the shared errors above:

ErrorMeaningFix
NotShortable(symbol)No Stock Token, no pool to short through, or no lending vaultPick another asset
InvalidPool(token, fee)The router's factory has no pool of the token and USDG at that feeOwner-side
InsufficientCollateral(amount)The short holds less than amount of USDGAsk for less, or deposit
Insolvent()The short owes more of the buy-in cost than it holdsOnly a liquidation closes it
DeficitOpen()Another short of the book owes more than it holds, so the book cannot pay outWait until that short is liquidated
NoShort()The account has no short of the assetCheck the account and asset
NotShortfall(equity, requirement)A liquidation of a short whose equity is not below its requirementNot liquidatable
AboveLimit()The pool asks more than a liquidation may payRetry later
NotLending(caller)The caller is not the asset's lending vaultNot a caller error
LengthMismatch()The fees are not one per assetOwner-side

A sale that the pool would fill below minProceeds, or a buy-back above maxCost, reverts in the router with Error("Too little received") or Error("Too much requested"). Quote again with quoteSale or quoteCover, or accept more slippage.

GapCover#

ErrorMeaningFix
NotCoverable(symbol)The engine has no Chainlink feed in the band for the assetPick another asset
SalesClosed()No cover is sold nowWait for the sales window before a closure
InvalidHolder()The holder is the zero addressPass a holder
InvalidLayer(deductibleBps, limitBps, minimum)The deductible must be at least minimum and below the limit, and the limit at most 10,000 basis pointsFix the layer; gapCover.minDeductible reads the minimum
StaleReference(deductibleBps, minimum)The feed's last answer stands above the band's centre, so the deductible must be at least minimumRaise the deductible
PremiumAboveLimit(premium, maxPremium)The premium is above the buyer's limitQuote again with gapCover.quote and raise maxPremium
NoCapacity(need, free)The cover would reserve more of the writers' USDG than is freeBuy less; gapCover.capacity reads it
NothingCovered(symbol, closesMs)No cover was sold on the seriesNothing to settle
SeriesClosed(symbol, closesMs)The series settled or is voidNothing to do
NotReopened(closesMs)The reopen is not recorded or not yet reachedWait, then record
WindowOpen(endMs), WindowClosed(endMs)The settlement window ends at, or ended at, endMsCall within the window
InvalidReference(roundId), InvalidLastRound(roundId)The round is not the feed's last round started before the close or before the reopenName the right rounds in settle
TooEarlyToVoid(fromMs), TooEarlyToMeasure(fromMs)The call opens only from fromMsWait
InsufficientGas()A read of a Chainlink feed ran out of gasSend with more gas
NoCover(id)The cover does not exist or was releasedCheck the id
NotSettled(id)The cover's series has not settledWait for settlement

Liquidator#

ErrorMeaningFix
NotLiquidatable(account, position)The position meets its requirement, or cannot be judged nowNothing to liquidate
CannotJudge(account, position)A held asset is halted or its multiplier change is unconfirmed, or the sequencer is not settledWait
NoAuction(account, position)No auction runs on the positionStart one, if it is liquidatable
StillShort(account, position)The auction still runs on a position that falls shortNot stoppable
NotForSale(token)The token is not sold in auctions; USDG settles through settleCashCall settleCash
CostAboveLimit(cost, maxCost)The purchase costs more than maxCostRaise maxCost or wait for the price to fall
NothingToBuy()The position owes nothing, holds none of the token, or the hour's share is spentWait for the next hour
NothingToRecall()The position lent none of the token that it has not recalled, or less than the least recallNothing to recall
PositionHeld(account, position, until)The reopening auction holds the position until untilWait
NotBackstop, NotAuction, NotAccountsOwner, AuctionAlreadySet, InvalidAuctionReserved or set-once callsNot a caller error

ReopeningAuction#

ErrorMeaningFix
WrongPhase()The session or the clock is not in the phase the call needsCheck auction.phase; commit, reveal and clear each have a window
WrongState()The round is cleared already, or cannot be claimed yetWait for the clearing
NoPrice(symbol)The band of the asset gives no priceWait for a price write
NotEnrollable(account, position)The position meets its requirement at its bands' low edges, can sell none of the Stock Token, or has a lot in the round alreadyNot enrollable
TooManyLots()The round sells its maximum lots, none smaller than this oneNot enrollable
InvalidCommitment(commitment)The commitment is pending already, or its deposit is below the bondRaise the deposit; auction.constants reads the bond
UnknownCommitment(commitment)No pending commitment matches the bidReveal with the exact quantity, price and salt that auction.commitment hashed
InvalidBid()The bid is below the floor, worth less than the minimum bid at the floor, or more than its depositBid within the limits; auction.previewFloor reads the floor
NotClearingPrice(price)The price is not the round's clearing priceCompute it with auction.clearingPrice
UnknownAsset(symbol), InvalidFeeds()The accounts have no Stock Token for the symbol, or the feeds do not matchCheck the asset

GapBackstop, SupplyVault and StockLendingVault#

ErrorMeaningFix
InvalidPosition(position)The position is neither CROSS nor an asset of the accountsUse a real position
InvalidExposureLimits()The limits do not match the accounts' assetsOwner-side
NotAuction(caller)Only the liquidator's reopening auction mayNot a caller error
InsufficientLiquidity(requested, available)The vault holds, or may lend, less than requestedAsk for at most available
NotBorrower(account), NotDepositor(account)The caller is not the vault's borrower or depositorNot a caller error
BorrowerAlreadySet, InvalidBorrower, AlreadySet, InvalidAddress, InvalidRateModel, InvalidFeeShareSet-once wiring or owner arguments out of rangeNot a caller error
NotDue()A recall ticket's notice has not run out, the vault holds all of the queue up to its end, or the borrower owes nothingWait for the notice
NotHead(head)Only the ticket next in turn may be given upUse ticket head
BuyInFailed(outstanding)The borrower's buy-in left outstanding unreturnedThe borrower returns the rest of what it was asked
Unavailable()The token is paused, the vault is blocklisted or its tokens were burnedNothing can come back until the issuer lifts it
OutOfReach(assets, reachable)The depositor may take only reachable of the vault's tokens with these ticketsTake at most reachable

Basket#

ErrorMeaningFix
AboveMaximum(token, amount, maxAmount)A mint would take more of a token than the caller's maxAmountRead baskets.previewMint and pass at least that as maxAssets
ComponentPaused()One of the basket's tokens is paused, and a share moves only as its tokens couldWait for the issuer
EmptyBasket()Every token the basket holds was burnedIt takes no mint
UnknownAsset(symbol), DuplicateComponent(symbol), InvalidComponents(), InvalidTarget(), LengthMismatch()Construction or target arguments out of rangeNot a caller error
PastTarget(symbol)A rebalance would take the asset past its target, or away from itOwner-side
ValueLost(valueIn, valueOut)A rebalance would take more value out at the high edges than it gets in at the low edgesOwner-side

Band, BandFeed and the Morpho oracle#

ErrorMeaningFix
NoAnswer(symbol)The band of the asset is halted, or has no live leg, most often because no one wrote a 24/7 price for two minutes while the market is closedband.writePrices a fresh payload. A Morpho oracle returns this as no price, never zero
NoRound(roundId)Only the current round, the block's timestamp, has an answerRead latestRound
NotSealWindow(session, reopenMs)A band is sealed only while the session is closed, within the window before its reopenCall seal in the ten minutes before the reopen
UnknownAsset(symbol)The band does not configure the symbolCheck the asset
NoToken(symbol)The asset has no Stock TokenPick another asset
InvalidToken(token)The Stock Token's multipliers cannot be readNot a caller error
PoolWithoutToken(pool, token), PoolNotInitialized(pool)The pool does not trade the asset's token, or was never initialisedNot a caller error
NoStockToken(band, symbol), AssetMismatch(band, token), ScaleTooLarge(scaleFactor)The Morpho oracle's band names no token, another token, or the scale could overflowOwner-side

writePrices also reverts with RedStone's payload checks:

ErrorMeaning
CalldataMustHaveValidPayload(), CalldataOverOrUnderFlow(), IncorrectUnsignedMetadataSize()The payload is malformed, truncated or does not end with RedStone's marker
InvalidSignature(signedHash), SignerNotAuthorised(receivedSigner)A package's signature does not recover, or its signer is outside RedStone's primary production set
InsufficientNumberOfUniqueSigners(received, required)A feed has fewer unique signers than the band requires
TooLargeValueByteSize(valueByteSize), DataTimestampCannotBeZero(), TimestampsMustBeEqual()A value is over 32 bytes, a package has no timestamp, or the packages' timestamps differ
TimestampFromTooLongFuture(received, blockTimestamp), TimestampIsTooOld(received, blockTimestamp)The packages are more than a minute ahead of the block, or more than three minutes behind it. Fetch a fresh payload
PackageNotNewer(feedId, storedTimestampMs, packageTimestampMs)The band stores a package of the feed at least as new. Another writer got there first
IncompleteStatus()The three market-status feeds are written together or not at all
HaltOutsideWindow(issuedAt, expiresAt, blockTimestamp), HaltNotNewer(symbol, storedIssuedAt, issuedAt)A halt message must be issued no later than now, expire after now and span at most an hour, and be newer than the stored one

Stock Tokens and USDG#

ErrorMeaning
IsPaused()The issuer paused the Stock Token
Blocked(account)The issuer's registry blocks the account
AccessControlUnauthorizedAccount(account, neededRole)The account lacks the role the call needs
ContractPaused()USDG is paused: transfers, approvals and permits revert
AddressFrozen()A frozen address neither sends nor receives USDG

Next#