Error Codes

Reference for all error codes returned by the active escrow-mainnet-v3 (mainnet) and escrow-v8 (testnet) contracts. Older contract versions (v6/v7, escrow-mainnet, escrow-mainnet-v2) use a similar scheme; the frontend's error mapping handles both.

Authorization (1xxx)

CodeConstantDescription
u1001ERR_UNAUTHORIZEDCaller is not the buyer / seller / beneficiary / admin for this action.
u1002ERR_CONTRACT_PAUSEDContract is currently paused. Create / deliver / release / refund / dispute / extend are all blocked until the pause lifts. Admin dispute resolution and seller self-rescue still work.
u1003ERR_OWNERSHIP_PENDINGOwnership transfer is in progress; the new owner has not yet accepted.
u1004ERR_NOT_PENDING_OWNEROnly the address designated as the pending new owner can accept ownership.

Escrow State (2xxx)

CodeConstantDescription
u2001ERR_ESCROW_NOT_FOUNDNo escrow exists with the given ID.
u2002ERR_ESCROW_ALREADY_COMPLETEDEscrow has already been released, refunded, or otherwise finalised. Most commonly a race: the counterparty acted first.
u2003ERR_ESCROW_EXPIREDThe deadline has passed. Buyer can refund instead of releasing.
u2004ERR_ESCROW_NOT_EXPIREDThe deadline has not yet been reached. Refund / seller self-rescue paths reject until expiry.
u2005ERR_INVALID_AMOUNTAmount outside the allowed bounds for the token type (see Protocol Numbers in the introduction).
u2006ERR_INVALID_DURATIONDuration outside MIN_DURATION..MAX_DURATION (1 burn block to ~365 days on v3+).
u2007ERR_SELF_ESCROWBuyer address equals seller address.
u2008ERR_DISPUTE_NOT_TIMED_OUTBuyer tried to claim an expired dispute before the dispute timeout elapsed.
u2009ERR_NOT_DISPUTEDCaller tried to resolve a dispute on an escrow that has no active dispute.
u2010ERR_INVALID_EXTENSIONDuration extension is zero or pushes total duration past the max.
u2011ERR_INVALID_TIMEOUTAdmin tried to set dispute-timeout outside its allowed range (1..MAX_DISPUTE_TIMEOUT).
u2012ERR_INVALID_TOKENToken-type uint is neither 0 (STX) nor 1 (sBTC).
u2013ERR_INVALID_BPSBasis-point value out of range (0..10000 for split resolutions, 0..MAX_FEE_BPS for fee setting).
u2014ERR_IN_REVIEW_PERIODBuyer attempted to refund during the post-delivery review window. Must wait for the window to lapse or raise a dispute.
u2015ERR_INVALID_STATUSAction incompatible with current escrow status (e.g. trying to deliver a Released escrow).
u2016ERR_NOT_DELIVEREDSeller tried to self-rescue without first signaling delivery on-chain.
u2017ERR_SELF_BENEFICIARYBeneficiary address equals buyer or seller — must be a distinct third party.

Transfer (3xxx)

CodeConstantDescription
u3001ERR_TRANSFER_FAILEDSTX or sBTC transfer? call reverted. Usually a wallet balance issue or a post-condition mismatch.
u3002ERR_INSUFFICIENT_BALANCEContract noticed a balance shortfall mid-transfer.

v3+ Specific (4xxx)

These codes only fire on escrow-mainnet-v3 and escrow-v8.

CodeConstantDescription
u4001ERR_INVALID_PAUSE_DURATIONAdmin called pause-contract(duration) with duration = 0 or duration > MAX_PAUSE_DURATION.
u4002ERR_SWEEP_EXCEEDS_FREE_BALANCEAdmin tried to sweep-orphans more than the un-locked balance. The contract enforces amount ≤ balance − total_locked so active escrows are never touched.
u4003ERR_PAUSE_COOLDOWN_ACTIVEAdmin tried to re-pause while the anti-chaining cooldown from a previous pause is still active. Cooldown ends 2 × duration blocks after the original pause confirmed.

Frontend handling

The frontend's categorizeTxError helper maps these codes to friendly toast messages. Wallet-rejection and network errors are caught first; then any uXXXX string in the wallet's error message is matched against this table.

typescript
// Example mappings shipped with the frontend: if (err.includes('u1002')) return { title: 'Contract is paused', ... }; if (err.includes('u4003')) return { title: 'Pause cooldown still active', ... }; if (err.includes('u2014')) return { title: 'Review period active', ... }; if (err.includes('u2017')) return { title: 'Beneficiary must differ', ... };

SDK handling

typescript
import { EscrowClient } from 'sbtc-escrow-sdk'; try { await client.createEscrow({ /* … */ }); } catch (error) { // Stacks contract errors come back as strings like "(err u2007)" or // the wallet's error message containing the code. Match on substring. const msg = error instanceof Error ? error.message : String(error); if (msg.includes('u2007')) { console.log('Cannot create an escrow to yourself'); } else if (msg.includes('u1002')) { console.log('Contract is paused'); } }

Notes on legacy contracts

escrow-v6 and escrow-mainnet use a different error code scheme (1000-5001 range, kebab-case err-not-sender names). The frontend handles both; if you're calling those contracts directly via the SDK, refer to the inline contract source in contracts/escrow-v6.clar or the explorer for the exact mapping.