{"templateId":"markdown","sharedDataIds":{},"props":{"metadata":{"markdoc":{"tagList":["sub-heading"]},"type":"markdown"},"seo":{"title":"Error handling","description":"Transform your commerce with PXP's unified platform—seamless payments, real-time insights, and global growth in one powerful integration.","lang":"en-UK","siteUrl":"https://developer.pxp.io","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"error-handling","__idx":0},"children":["Error handling"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement robust error handling for seamless payment experiences."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The Android SDK provides comprehensive error handling mechanisms to help you create resilient payment experiences."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["By implementing proper error handling, you can:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Provide clear user feedback with meaningful error messages."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Implement retry logic for transient failures."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track and diagnose issues for improved reliability."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Handle edge cases gracefully without crashes."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Maintain payment flow continuity through error recovery."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The SDK uses a hierarchical error system with standardised error codes, making it easy to handle different error types consistently across your application."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"error-architecture","__idx":2},"children":["Error architecture"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"error-hierarchy","__idx":3},"children":["Error hierarchy"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All SDK errors inherit from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BaseSdkException"]},", providing a consistent structure:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"open class BaseSdkException(\n    message: String,\n    cause: Throwable? = null,\n    val errorCode: String\n) : Exception(message, cause)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"error-categories","__idx":4},"children":["Error categories"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The SDK organises errors into logical categories with standardised codes:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"object SdkErrorCodes {\n    // 00: Common Errors\n    const val UNEXPECTED_ERROR = \"SDK0000\"\n    const val NOT_IMPLEMENTED = \"SDK0001\"\n    const val VALIDATION_ERROR = \"SDK0002\"\n    \n    // 01: SDK Errors\n    const val SDK_CONFIG_EMPTY = \"SDK0100\"\n    const val SDK_CONFIG_ENVIRONMENT_EMPTY = \"SDK0101\"\n    const val SDK_CONFIG_SESSION_EMPTY = \"SDK0102\"\n    \n    // 02: Component Errors\n    const val COMPONENT_ERROR = \"SDK0200\"\n    const val COMPONENT_CONFIG_NAME_EMPTY = \"SDK0201\"\n    const val COMPONENT_CONTAINER_NOT_FOUND = \"SDK0202\"\n    \n    // 03: Token Vault Errors\n    const val TOKEN_VAULT_ERROR = \"SDK0300\"\n    const val TOKENIZE_CARD_ERROR = \"SDK0301\"\n    const val RETRIEVE_TOKENS_ERROR = \"SDK0302\"\n    \n    // 04: ThreeDSecure Errors\n    const val AUTHENTICATION_FAILED = \"SDK0505\"\n    const val PRE_INITIATE_INTEGRATED_AUTHENTICATION_CURRENCY_CODE_INVALID = \"SDK0400\"\n    \n    // 05: Transaction Errors\n    const val NETWORK_ERROR = \"SDK0500\"\n    const val VALIDATION_ERROR = \"SDK0501\"\n    const val PARSE_ERROR = \"SDK0502\"\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"common-error-types","__idx":5},"children":["Common error types"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"validation-errors","__idx":6},"children":["Validation errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle validation failures for user input:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class ValidationErrorHandler {\n    \n    fun handleValidationError(exception: ComponentValidationException) {\n        when (exception.errorCode) {\n            SdkErrorCodes.VALIDATION_ERROR -> {\n                // Display field-specific validation messages\n                exception.validationResults.forEach { result ->\n                    if (!result.isValid) {\n                        showFieldError(result.fieldName, result.errorMessage)\n                    }\n                }\n            }\n            SdkErrorCodes.MISSING_REQUIRED_FIELD -> {\n                showError(\"Please fill in all required fields\")\n            }\n            SdkErrorCodes.INVALID_INPUT -> {\n                showError(\"Please check your input and try again\")\n            }\n        }\n    }\n    \n    private fun showFieldError(fieldName: String, message: String) {\n        Log.e(\"Validation\", \"Field '$fieldName': $message\")\n        // Update UI to show field-specific error\n        updateFieldErrorState(fieldName, message)\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"network-errors","__idx":7},"children":["Network errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle connectivity and API-related issues:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class NetworkErrorHandler {\n    \n    fun handleNetworkError(exception: BaseSdkException) {\n        when (exception.errorCode) {\n            ErrorCode.NETWORK_ERROR -> {\n                Log.e(\"Network\", \"Network connection error: ${exception.message}\")\n                showRetryableError(\"No internet connection. Please check your connection and try again.\")\n            }\n            ErrorCode.TIMEOUT_ERROR -> {\n                Log.e(\"Network\", \"Request timeout: ${exception.message}\")\n                showRetryableError(\"Request timed out. Please try again.\")\n            }\n            ErrorCode.HTTP_ERROR -> {\n                Log.e(\"Network\", \"HTTP error: ${exception.message}\")\n                showError(\"Server error. Please try again later.\")\n            }\n            ErrorCode.API_ERROR -> {\n                Log.e(\"Network\", \"API error: ${exception.message}\")\n                showError(\"Service temporarily unavailable. Please try again.\")\n            }\n            else -> {\n                Log.e(\"Network\", \"Unknown network error: ${exception.message}\")\n                showError(\"Connection error. Please try again.\")\n            }\n        }\n    }\n    \n    private fun showRetryableError(message: String) {\n        // Show error with retry button\n        showErrorDialog(message, showRetryButton = true)\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3ds-authentication-errors","__idx":8},"children":["3DS authentication errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle 3D Secure authentication failures:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class ThreeDSErrorHandler {\n    \n    fun handleAuthenticationError(exception: BaseSdkException) {\n        when (exception.errorCode) {\n            \"SDK0505\" -> { // AUTHENTICATION_FAILED\n                Log.e(\"3DS\", \"Authentication failed: ${exception.message}\")\n                showError(\"Authentication failed. Please try again or contact your bank.\")\n            }\n            \"SDK0502\" -> { // PRE_INITIATE_AUTHENTICATION_FAILED\n                Log.e(\"3DS\", \"Pre-initiate authentication failed: ${exception.message}\")\n                showError(\"Unable to start authentication. Please try again.\")\n            }\n            \"SDK0503\" -> { // TRANSACTION_AUTHENTICATION_REJECTED\n                Log.e(\"3DS\", \"Authentication rejected: ${exception.message}\")\n                showError(\"Authentication was rejected. Please contact your bank.\")\n            }\n            \"SDK0504\" -> { // TRANSACTION_AUTHENTICATION_REQUIRE_SCA_EXEMPTION\n                Log.e(\"3DS\", \"SCA exemption required: ${exception.message}\")\n                handleScaExemptionRequired()\n            }\n            else -> {\n                Log.e(\"3DS\", \"Unknown authentication error: ${exception.message}\")\n                showError(\"Authentication error. Please try again.\")\n            }\n        }\n    }\n    \n    private fun handleScaExemptionRequired() {\n        // Handle SCA exemption requirement\n        showError(\"Additional authentication required. Please contact support.\")\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"component-errors","__idx":9},"children":["Component errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle component initialisation and lifecycle errors:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class ComponentErrorHandler {\n    \n    fun handleComponentError(exception: ComponentException) {\n        Log.e(\"Component\", \"Component error in ${exception.componentType}: ${exception.message}\")\n        \n        when (exception.errorCode) {\n            SdkErrorCodes.COMPONENT_ERROR -> {\n                showError(\"Component initialisation failed. Please refresh and try again.\")\n            }\n            SdkErrorCodes.COMPONENT_CONFIG_NAME_EMPTY -> {\n                Log.e(\"Component\", \"Component configuration error: missing name\")\n                showError(\"Configuration error. Please contact support.\")\n            }\n            SdkErrorCodes.COMPONENT_CONTAINER_NOT_FOUND -> {\n                Log.e(\"Component\", \"Component container not found\")\n                showError(\"UI error. Please refresh and try again.\")\n            }\n            else -> {\n                showError(\"Component error. Please try again.\")\n            }\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"token-vault-errors","__idx":10},"children":["Token Vault errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle card tokenisation and storage issues:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class TokenVaultErrorHandler {\n    \n    fun handleTokenVaultError(exception: BaseSdkException) {\n        when (exception.errorCode) {\n            SdkErrorCodes.TOKENIZE_CARD_ERROR -> {\n                Log.e(\"TokenVault\", \"Card tokenisation failed: ${exception.message}\")\n                showError(\"Unable to process card details. Please check your information and try again.\")\n            }\n            SdkErrorCodes.RETRIEVE_TOKENS_ERROR -> {\n                Log.e(\"TokenVault\", \"Failed to retrieve saved cards: ${exception.message}\")\n                showError(\"Unable to load saved payment methods. Please try again.\")\n            }\n            SdkErrorCodes.DELETE_TOKEN_ERROR -> {\n                Log.e(\"TokenVault\", \"Failed to delete saved card: ${exception.message}\")\n                showError(\"Unable to remove payment method. Please try again.\")\n            }\n            SdkErrorCodes.UPDATE_TOKEN_ERROR -> {\n                Log.e(\"TokenVault\", \"Failed to update saved card: ${exception.message}\")\n                showError(\"Unable to update payment method. Please try again.\")\n            }\n            SdkErrorCodes.ENCRYPTION_ERROR -> {\n                Log.e(\"TokenVault\", \"Encryption error: ${exception.message}\")\n                showError(\"Security error. Please try again.\")\n            }\n            else -> {\n                Log.e(\"TokenVault\", \"Unknown token vault error: ${exception.message}\")\n                showError(\"Payment method error. Please try again.\")\n            }\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"implementation-patterns","__idx":11},"children":["Implementation patterns"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"centralised-error-handling","__idx":12},"children":["Centralised error handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a central error handler for consistent error management:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class PxpErrorHandler {\n    \n    fun handleError(error: Throwable) {\n        val baseSdkException = when (error) {\n            is BaseSdkException -> error\n            is Exception -> {\n                if (error.message == \"NetWorkError\") {\n                    NetworkSdkException(error)\n                } else {\n                    UnexpectedSdkException(error)\n                }\n            }\n            else -> UnexpectedSdkException(error)\n        }\n        \n        when (baseSdkException) {\n            is ComponentValidationException -> ValidationErrorHandler().handleValidationError(baseSdkException)\n            is AuthenticationFailedException -> ThreeDSErrorHandler().handleAuthenticationError(baseSdkException)\n            is ComponentException -> ComponentErrorHandler().handleComponentError(baseSdkException)\n            else -> handleGenericError(baseSdkException)\n        }\n        \n        // Track error for analytics\n        trackError(baseSdkException)\n    }\n    \n    private fun handleGenericError(exception: BaseSdkException) {\n        Log.e(\"PxpError\", \"Generic error: ${exception.message} (${exception.errorCode})\")\n        showError(\"An error occurred. Please try again.\")\n    }\n    \n    private fun trackError(exception: BaseSdkException) {\n        // Track error for analytics and monitoring\n        analytics.track(\"payment_error\", mapOf(\n            \"error_code\" to exception.errorCode,\n            \"error_message\" to exception.message,\n            \"error_type\" to exception::class.simpleName\n        ))\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"component-specific-error-handling","__idx":13},"children":["Component-specific error handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement error handling in component configurations:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"val cardSubmitConfig = CardSubmitComponentConfig(\n    // Handle submission errors\n    onSubmitError = { exception ->\n        when (exception.errorCode) {\n            SdkErrorCodes.VALIDATION_ERROR -> {\n                Log.e(\"CardSubmit\", \"Validation failed: ${exception.message}\")\n                showValidationErrors()\n            }\n            ErrorCode.NETWORK_ERROR -> {\n                Log.e(\"CardSubmit\", \"Network error during submission: ${exception.message}\")\n                showRetryOption(\"Network error. Please check your connection and try again.\")\n            }\n            else -> {\n                Log.e(\"CardSubmit\", \"Submission error: ${exception.message}\")\n                showError(\"Payment failed. Please try again.\")\n            }\n        }\n    },\n    \n    // Handle validation results\n    onValidation = { validationResults ->\n        val hasErrors = validationResults.any { !it.isValid }\n        if (hasErrors) {\n            handleValidationErrors(validationResults)\n        } else {\n            clearValidationErrors()\n        }\n    },\n    \n    // Handle authorisation results\n    onPostAuthorisation = { result ->\n        when (result) {\n            is FailedSubmitResult -> {\n                Log.e(\"CardSubmit\", \"Payment failed: ${result.errorReason}\")\n                handlePaymentFailure(result)\n            }\n            is RefusedSubmitResult -> {\n                Log.w(\"CardSubmit\", \"Payment refused: ${result.stateData.message}\")\n                handlePaymentRefused(result)\n            }\n            // Handle success cases...\n        }\n    }\n)\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"retry-mechanisms","__idx":14},"children":["Retry mechanisms"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement intelligent retry logic for transient failures:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class PaymentRetryManager {\n    private var retryCount = 0\n    private val maxRetries = 3\n    private val retryDelays = listOf(1000L, 2000L, 5000L) // Progressive delays\n    \n    fun handleRetryableError(error: BaseSdkException, retryAction: () -> Unit) {\n        if (shouldRetry(error) && retryCount < maxRetries) {\n            val delay = retryDelays.getOrElse(retryCount) { 5000L }\n            retryCount++\n            \n            Log.w(\"Retry\", \"Retrying operation in ${delay}ms (attempt $retryCount/$maxRetries)\")\n            showRetryMessage(\"Retrying... (${retryCount}/$maxRetries)\")\n            \n            // Delay and retry\n            Handler(Looper.getMainLooper()).postDelayed({\n                retryAction()\n            }, delay)\n        } else {\n            // Max retries reached or non-retryable error\n            retryCount = 0\n            handleFinalFailure(error)\n        }\n    }\n    \n    private fun shouldRetry(error: BaseSdkException): Boolean {\n        return when (error.errorCode) {\n            ErrorCode.NETWORK_ERROR,\n            ErrorCode.TIMEOUT_ERROR,\n            ErrorCode.HTTP_ERROR -> true\n            else -> false\n        }\n    }\n    \n    private fun handleFinalFailure(error: BaseSdkException) {\n        Log.e(\"Retry\", \"Max retries reached for error: ${error.message}\")\n        showError(\"Unable to complete payment after multiple attempts. Please try again later.\")\n    }\n    \n    fun resetRetryCount() {\n        retryCount = 0\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["###User-friendly error messages"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Convert technical errors into user-friendly messages:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class ErrorMessageFormatter {\n    \n    fun formatUserMessage(exception: BaseSdkException): String {\n        return when (exception.errorCode) {\n            // Validation errors\n            SdkErrorCodes.VALIDATION_ERROR -> \"Please check your payment details and try again.\"\n            \"CARD_NUMBER_INVALID\" -> \"Please enter a valid card number.\"\n            \"CARD_EXPIRED\" -> \"This card has expired. Please use a different card.\"\n            \"CVC_INVALID\" -> \"Please enter a valid security code.\"\n            \n            // Network errors\n            ErrorCode.NETWORK_ERROR -> \"No internet connection. Please check your connection and try again.\"\n            ErrorCode.TIMEOUT_ERROR -> \"Request timed out. Please try again.\"\n            \n            // 3DS errors\n            \"SDK0505\" -> \"Card authentication failed. Please contact your bank for assistance.\"\n            \"SDK0503\" -> \"Authentication was declined. Please contact your bank.\"\n            \n            // Token vault errors\n            SdkErrorCodes.TOKENIZE_CARD_ERROR -> \"Unable to process card details. Please try again.\"\n            SdkErrorCodes.RETRIEVE_TOKENS_ERROR -> \"Unable to load saved payment methods.\"\n            \n            // Generic fallbacks\n            else -> \"Payment failed. Please try again or contact support.\"\n        }\n    }\n    \n    fun formatDeveloperMessage(exception: BaseSdkException): String {\n        return \"Error ${exception.errorCode}: ${exception.message}\"\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"error-recovery-strategies","__idx":15},"children":["Error recovery strategies"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"graceful-degradation","__idx":16},"children":["Graceful degradation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement fallback options when primary payment methods fail:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class PaymentFlowManager {\n    \n    fun handlePaymentFailure(error: BaseSdkException) {\n        when (error.errorCode) {\n            SdkErrorCodes.TOKENIZE_CARD_ERROR -> {\n                // Fallback to direct payment without tokenisation\n                Log.w(\"PaymentFlow\", \"Tokenisation failed, proceeding without saving card\")\n                showOption(\"Payment method won't be saved for future use. Continue?\") {\n                    proceedWithDirectPayment()\n                }\n            }\n            \"SDK0505\" -> { // 3DS authentication failed\n                // Fallback to non-3DS if supported\n                Log.w(\"PaymentFlow\", \"3DS failed, attempting non-3DS payment\")\n                showOption(\"Authentication failed. Try simplified payment?\") {\n                    proceedWithNon3DSPayment()\n                }\n            }\n            SdkErrorCodes.RETRIEVE_TOKENS_ERROR -> {\n                // Fallback to new card entry\n                Log.w(\"PaymentFlow\", \"Saved cards unavailable, using new card flow\")\n                showNewCardForm()\n            }\n            else -> {\n                // Generic retry option\n                showRetryOption(\"Payment failed. Would you like to try again?\") {\n                    retryPayment()\n                }\n            }\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"progressive-error-handling","__idx":17},"children":["Progressive error handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement escalating error handling based on failure count:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class ProgressiveErrorHandler {\n    private var consecutiveFailures = 0\n    \n    fun handleError(error: BaseSdkException) {\n        consecutiveFailures++\n        \n        when (consecutiveFailures) {\n            1 -> {\n                // First failure: Simple retry\n                showSimpleRetry(\"Payment failed. Please try again.\")\n            }\n            2 -> {\n                // Second failure: Suggest checking details\n                showDetailedRetry(\"Payment failed again. Please check your card details and try again.\")\n            }\n            3 -> {\n                // Third failure: Offer alternative payment methods\n                showAlternativeOptions(\"Multiple payment failures. Would you like to try a different payment method?\")\n            }\n            else -> {\n                // Multiple failures: Suggest contacting support\n                showSupportOption(\"We're having trouble processing your payment. Please contact support for assistance.\")\n            }\n        }\n    }\n    \n    fun resetFailureCount() {\n        consecutiveFailures = 0\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"best-practices","__idx":18},"children":["Best practices"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"error-logging-and-monitoring","__idx":19},"children":["Error logging and monitoring"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement comprehensive error tracking:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class ErrorTracker {\n    \n    fun trackError(error: BaseSdkException, context: Map<String, Any> = emptyMap()) {\n        // Log to console for debugging\n        Log.e(\"PxpError\", \"Error ${error.errorCode}: ${error.message}\", error)\n        \n        // Send to crash reporting\n        crashlytics.recordException(error)\n        \n        // Track in analytics\n        analytics.track(\"payment_error\", mapOf(\n            \"error_code\" to error.errorCode,\n            \"error_message\" to error.message,\n            \"error_type\" to error::class.simpleName,\n            \"timestamp\" to System.currentTimeMillis(),\n            \"user_id\" to getCurrentUserId(),\n            \"session_id\" to getCurrentSessionId()\n        ) + context)\n        \n        // Send to monitoring service\n        monitoringService.recordError(error, context)\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"user-experience-considerations","__idx":20},"children":["User experience considerations"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Prioritise user experience in error handling:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class UserExperienceErrorHandler {\n    \n    fun handleErrorWithUX(error: BaseSdkException) {\n        // Hide loading indicators\n        hideLoadingStates()\n        \n        // Vibrate for tactile feedback on errors\n        if (shouldVibrateOnError(error)) {\n            vibrate(100)\n        }\n        \n        // Choose appropriate display method\n        when (error.errorCode) {\n            SdkErrorCodes.VALIDATION_ERROR -> {\n                // Show inline field errors\n                showInlineErrors()\n            }\n            ErrorCode.NETWORK_ERROR -> {\n                // Show toast for temporary issues\n                showToast(formatUserMessage(error))\n            }\n            else -> {\n                // Show dialog for serious errors\n                showErrorDialog(formatUserMessage(error))\n            }\n        }\n        \n        // Re-enable form interactions\n        enableFormInteractions()\n    }\n    \n    private fun shouldVibrateOnError(error: BaseSdkException): Boolean {\n        // Only vibrate for user-actionable errors\n        return when (error.errorCode) {\n            SdkErrorCodes.VALIDATION_ERROR,\n            \"CARD_NUMBER_INVALID\",\n            \"CVC_INVALID\" -> true\n            else -> false\n        }\n    }\n}\n","lang":"kotlin"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"testing-error-scenarios","__idx":21},"children":["Testing error scenarios"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test error handling thoroughly:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"class ErrorHandlingTests {\n    \n    @Test\n    fun testValidationErrorHandling() {\n        // Simulate validation error\n        val validationError = ComponentValidationException(\n            componentType = \"CardNumber\",\n            validationResults = listOf(\n                ValidationResult(\n                    fieldName = \"cardNumber\",\n                    isValid = false,\n                    errorMessage = \"Invalid card number\"\n                )\n            )\n        )\n        \n        errorHandler.handleError(validationError)\n        \n        // Verify UI shows error\n        verify { mockUI.showFieldError(\"cardNumber\", \"Invalid card number\") }\n    }\n    \n    @Test\n    fun testNetworkErrorRetry() {\n        val networkError = NetworkSdkException(\"Connection timeout\")\n        \n        errorHandler.handleError(networkError)\n        \n        // Verify retry mechanism is triggered\n        verify { mockRetryManager.scheduleRetry(any()) }\n    }\n}\n","lang":"kotlin"},"children":[]}]},"headings":[{"value":"Error handling","id":"error-handling","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Error architecture","id":"error-architecture","depth":2},{"value":"Error hierarchy","id":"error-hierarchy","depth":3},{"value":"Error categories","id":"error-categories","depth":3},{"value":"Common error types","id":"common-error-types","depth":2},{"value":"Validation errors","id":"validation-errors","depth":3},{"value":"Network errors","id":"network-errors","depth":3},{"value":"3DS authentication errors","id":"3ds-authentication-errors","depth":3},{"value":"Component errors","id":"component-errors","depth":3},{"value":"Token Vault errors","id":"token-vault-errors","depth":3},{"value":"Implementation patterns","id":"implementation-patterns","depth":2},{"value":"Centralised error handling","id":"centralised-error-handling","depth":3},{"value":"Component-specific error handling","id":"component-specific-error-handling","depth":3},{"value":"Retry mechanisms","id":"retry-mechanisms","depth":3},{"value":"Error recovery strategies","id":"error-recovery-strategies","depth":2},{"value":"Graceful degradation","id":"graceful-degradation","depth":3},{"value":"Progressive error handling","id":"progressive-error-handling","depth":3},{"value":"Best practices","id":"best-practices","depth":2},{"value":"Error logging and monitoring","id":"error-logging-and-monitoring","depth":3},{"value":"User experience considerations","id":"user-experience-considerations","depth":3},{"value":"Testing error scenarios","id":"testing-error-scenarios","depth":3}],"frontmatter":{"seo":{"title":"Error handling"}},"lastModified":"2026-02-26T12:14:32.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/components/android/card/error-handling","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}