Skip to content

Errors

How Exchange Pay failures surface in React and what to do at each step.

How errors surface

  1. Hook error stateuseExchangePaySupportedCurrencies().error, useExchangePayOrder().error, amount validation via useExchangePayAmount().error.
  2. Thrown / rejected promisescreateOrder / closeOrder / getOrder / refetch also reject.
  3. EventsuseOnExchangePayOrderExpired is not an error, but you must handle it in UI.

Amount validation errors

useExchangePayAmount().error is an AmountValidationError ({ code, message, metadata }), not a string. Switch on code for i18n:

tsx
import type { AmountValidationError } from '@swapped/connect-sdk'
import { useExchangePayAmount } from '@swapped/connect-sdk/react'

function AmountError() {
  const { error } = useExchangePayAmount()
  if (!error) return null

  const text = translateAmountError(error)
  return <p>{text}</p>
}

function translateAmountError(error: AmountValidationError): string {
  switch (error.code) {
    case 'below_min':
      return `Min amount ${error.metadata.formattedMinAmount}`
    case 'above_spendable':
      return `Max amount ${error.metadata.formattedMaxAmount}`
    case 'above_balance':
      return `Balance is ${error.metadata.formattedBalanceAmount}`
    default:
      return error.message
  }
}

Typed SDK failures are ConnectSdkError with a stable code:

tsx
import { ConnectSdkError, ConnectSdkErrorCode } from '@swapped/connect-sdk'
import { useExchangePayOrder } from '@swapped/connect-sdk/react'

function CreateWithErrors() {
  const { createOrder, error, isCreating } = useExchangePayOrder()

  async function onSubmit() {
    try {
      await createOrder()
    } catch (err) {
      if (
        err instanceof ConnectSdkError &&
        err.code === ConnectSdkErrorCode.SESSION_NOT_ACTIVE
      ) {
        // Call restartSession() via useSwappedConnectClient()
      }
    }
  }

  return (
    <div>
      {error && <p>{error.message}</p>}
      <button type="button" disabled={isCreating} onClick={() => void onSubmit()}>
        Pay
      </button>
    </div>
  )
}

When things fail in the flow

StepWhat goes wrongHow you see itWhat to do in UI
Mount hooksOutside ExchangePayContextProviderREACT_EXCHANGE_PAY_PROVIDER_REQUIREDWrap with the provider
Load currenciesAPI / network failurecurrencies error / API_ERRORRetry refetch
Create orderIncomplete selectionEXCHANGE_PAY_SELECTION_INCOMPLETESelect provider, currency, amount
Create orderSession already completedSESSION_NOT_ACTIVErestartSession() first
Create orderSession not loadedSESSION_REQUIREDloadSession()
Create orderAPI rejectionAPI_ERRORFix amount / retry
Checkout leaveClose API failedCLOSE_ACTIVE_ORDER_FAILEDRetry close or create again
Status / closeNo orderNO_ACTIVE_ORDERBack to form
WaitingTimed outuseOnExchangePayOrderExpired / isExpiredToast + navigate back; create a new order
After successCreate again without restartSESSION_NOT_ACTIVErestartSession()

Block amounts below minAmountFiat with useExchangePayAmount before createOrder.

Error code reference

CodeWhen it happensWhat to do
REACT_EXCHANGE_PAY_PROVIDER_REQUIREDHook used outside ExchangePayContextProviderWrap with ExchangePayContextProvider
EXCHANGE_PAY_SELECTION_INCOMPLETEcreateOrder() without provider / currency / amountComplete selection first
SESSION_REQUIREDNo loaded sessionCall loadSession()
SESSION_NOT_ACTIVESession cannot accept a new paymentrestartSession() before createOrder
NO_ACTIVE_ORDERStatus/close without an active ordercreateOrder first
CLOSE_ACTIVE_ORDER_FAILEDProvider close failedRetry close, or create a new order
API_ERRORCurrencies / create / status / close failureRetry
CLIENT_DESTROYEDClient already destroyedCreate a new client

canClose === false (Bybit, OKX): skip cancel UI — not an error.