Skip to content

Errors ​

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

How errors surface ​

  1. Hook error state - useExchangePaySupportedCurrencies().error, useExchangePayOrder().error, amount validation via useExchangePayAmount().error.
  2. Thrown / rejected promises - createOrder / closeOrder / getOrder / refetch also reject.
  3. Events - useOnExchangePayOrderExpired 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 replaced mid-flightSESSION_REPLACEDIgnore; the hook already reset
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 or above maxAmountFiat 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
SESSION_REPLACEDSession was replaced while create was in flightIgnore; the hook already reset
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.