Errors, Logging and Troubleshooting

WirexError codes and reasons, logging, timeouts and the common failures of the iOS SDK.

Before You Start

Read the following guides before proceeding:

GuideWhy
iOS SDKSurfaces, isolation model and flows
SDK Setupcreate(...) and the credential provider

Where Errors Arrive

SurfaceDelivery
Revealsnapshot.state .error(WirexError). load() throws only WirexDeclined or CancellationError; session(cardId:…) throws WirexError with reason invalidCardId
CollecttokenizeTopUp / tokenizeOctDestination throw WirexError
3-D Secureoutcome.error, code originRefused, declined or unavailable
Apple Pay.executeFailed(WirexWalletExecuteError) and .failed(WirexWalletError) events

WirexError

codeHandling
unauthorizedRefresh the access token. The SDK never retries a 401
actionRequiredObtain a fresh action token and retry
updateRequiredShip a newer SDK build
invalidInputFix the input — see reason
temporaryRetry when retryable is true
failedTerminal

retryable says whether a retry can help. reason adds detail where the API supplies one:

reasonMeaning
actionTokenRejectedThe API rejected the action token. Mint a fresh GetCardDetails token
cardAlreadyLinkedCollect: the card is already linked
cardLimitReachedCollect: the user holds the maximum number of saved cards
invalidCardIdReveal: the card id is malformed

e.detail.apiCode carries the API's own error code where present.

Other Types

  • WirexDeclined is not an error state: the user said no and nothing was sent.
  • WirexEnvironmentUnavailable is thrown by WirexEnvironment.resolve(_:chainId:) and
    WirexWalletEnvironment.resolve(_:): unknownName, notBuilt, malformedEndpoints, missingChainId. The
    create(...) factories return nil for the same conditions. Show the reason; never fall back to another
    environment.
func describe(_ error: Error) {
    if let e = error as? WirexError {
        print(e.code, e.retryable, e.reason as Any, e.detail.apiCode as Any)
    } else if let e = error as? WirexEnvironmentUnavailable {
        print(e)
    } else if error is WirexDeclined {
        print("user declined the step-up")
    }
}

Logging

Logging is off by default. Every logged value passes a redactor; tokens and card data are never handed to a
sink.

SurfaceOption
Reveal, Collectlogging: WirexLogging(level:sink:) on create(...). Presets: .disabled, .debug, osLogLogging(level:)
Apple PayWirexWalletLogging(level:sink:) with its own WirexWalletLogSink protocol
final class ConsoleLogSink: WirexLogSink {
    func write(level: WirexLogLevel, event: String, fields: [String: String]) { print(level, event, fields) }
}

let reveal = WirexReveal.create(
    credentials: credentials, chainId: "<chain id>",
    logging: WirexLogging(level: .info, sink: ConsoleLogSink()),
    timeouts: WirexTimeouts(requestSeconds: 20, resourceSeconds: 60))

Log at debug in development builds and warn in release.


Timeouts

timeouts: WirexTimeouts(requestSeconds:resourceSeconds:) on create(...) for Reveal and Collect.


Troubleshooting

SymptomCauseResolution
create(...) returns nilThe build has no endpoints for that environment, or chainId is emptyCall WirexEnvironment.resolve(_:chainId:) to get the reason
Reveal or Collect fails with unauthorizedStale bearer. The SDK never retries a 401Check expiry and refresh inside accessToken()
API answers 400 on every callBoth userEmail and userWallet are setReturn exactly one identity
A revealed field is blankSimulator secure layer, or a box shorter than naturalHeightTest on a device; size the box to naturalHeight
Collect cannot tokenizeBilling details missing, or the user is not enrolled at the acquirerSend every required billing field — see Collect a Card
The Pay button is unavailableChecker not started, empty provider block, or the SimulatorStart WirexWalletAvailabilityChecker with the real block; test on a device
3-D Secure ends in .pendingThe payment is not settled yetNot an error. Settle from the top-up status

Did this page help you?