Skip to content

Troubleshooting

Learn how to diagnose and fix common issues with the Google Pay Android component.

Exception types and error codes

Component exceptions

The Google Pay Android component throws specific exceptions for different error scenarios:

Exception Error codeDescription
GooglePayLoadFailedExceptionSDK0704The Google Pay API failed to load. For example, due to network issues, Google Play Services unavailable, or device incompatibility.
GooglePayNotReadyExceptionSDK0701Google Pay isn't ready on this device. For example, Google Play Services not installed, no Google account, or no payment methods configured.
GooglePayClientNotInitializedExceptionSDK0703The Google Pay client was not properly initialised before attempting a payment.
GooglePayConfigurationValidationFailedExceptionSDK0705Configuration validation failed. For example, missing required fields, invalid payment method configuration, or incorrect format.
GooglePayPaymentFailedExceptionSDK0702Payment processing failed. For example, due to network issues, declined payment, or server errors.
GooglePayDecryptAndTokenVaultFailedExceptionSDK0706Payment token decryption or vault storage failed. Check gateway configuration and token handling.
UnsupportedFundingTypeGooglePaySdkExceptionSDK0108Google Pay is not included in the allowed funding types for this session.

Payment cancellation by the user is not thrown as an exception. Instead, use the onCancel callback to handle user cancellations gracefully.

Error handling best practices

Comprehensive error handler

import android.util.Log
import com.pxp.checkout.components.googlepay.*
import com.pxp.checkout.services.kount.*
import com.pxp.checkout.models.*

val config = GooglePayButtonComponentConfig().apply {
    onError = { error ->
        // Log error for debugging
        Log.e("GooglePay", "Error: ${error::class.simpleName} - ${error.message}", error)
        
        // Handle specific error types
        val userMessage = when (error) {
            is GooglePayNotReadyException -> {
                showAlternativePaymentMethods()
                "Google Pay is not available on this device. Please use an alternative payment method."
            }
            is GooglePayConfigurationValidationFailedException -> {
                logCriticalError("Configuration validation error", error)
                "Payment system temporarily unavailable. Please try again in a few moments."
            }
            is GooglePayClientNotInitializedException -> {
                logCriticalError("Client not initialised", error)
                "Payment system not ready. Please refresh and try again."
            }
            is GooglePayLoadFailedException -> {
                "Unable to load payment system. Please check your connection and try again."
            }
            is GooglePayPaymentFailedException -> {
                "Payment failed. Please check your payment information and try again."
            }
            is GooglePayDecryptAndTokenVaultFailedException -> {
                logCriticalError("Token vault error", error)
                "Payment processing error. Please try again."
            }
            is UnsupportedFundingTypeGooglePaySdkException -> {
                showAlternativePaymentMethods()
                "Google Pay is not available for this session. Please use an alternative payment method."
            }
            else -> {
                logCriticalError("Unknown error", error)
                "An unexpected error occurred. Please try again or contact support."
            }
        }
        
        showErrorMessage(userMessage)
    }
    
    // Handle user cancellation separately (not an exception)
    onCancel = {
        Log.d("GooglePay", "User cancelled Google Pay")
    }
}

Troubleshooting common issues

Google Pay button isn't showing

The symptoms of this are:

  • The button is not rendered in the UI.
  • Empty space where the button should appear.
  • No Google Pay option is visible to customers.

Diagnostic steps

import android.accounts.AccountManager
import android.os.Build
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability

// Check Google Pay availability
fun checkGooglePayAvailability(context: Context): Boolean {
    Log.d("GooglePay", "Checking availability...")
    
    // Check Google Play Services
    val googleApiAvailability = GoogleApiAvailability.getInstance()
    val resultCode = googleApiAvailability.isGooglePlayServicesAvailable(context)
    
    if (resultCode != ConnectionResult.SUCCESS) {
        Log.e("GooglePay", "Google Play Services unavailable: $resultCode")
        return false
    }
    
    // Check Android version
    if (Build.VERSION.SDK_INT < 24) {
        Log.e("GooglePay", "Android version too low: ${Build.VERSION.SDK_INT}")
        return false
    }
    
    // Check for Google account
    val accountManager = AccountManager.get(context)
    val accounts = accountManager.getAccountsByType("com.google")
    
    if (accounts.isEmpty()) {
        Log.w("GooglePay", "No Google account found")
        return false
    }
    
    // Verify payment method configuration
    val config = getGooglePayConfig()
    val paymentMethods = config.paymentDataRequest.allowedPaymentMethods
    
    if (paymentMethods.isEmpty() || 
        paymentMethods[0].parameters.allowedCardNetworks.isEmpty()) {
        Log.e("GooglePay", "Invalid payment method configuration")
        return false
    }
    
    Log.d("GooglePay", "Google Pay is available")
    return true
}

Solutions

import androidx.compose.runtime.*
import com.pxp.checkout.PxpCheckout
import com.pxp.checkout.components.googlepay.*

// Solution 1: Graceful fallback
@Composable
fun AdaptivePaymentButtons(pxpCheckout: PxpCheckout) {
    val googlePayAvailable = remember {
        checkGooglePayAvailability(context)
    }
    
    if (googlePayAvailable) {
        GooglePayButton(pxpCheckout)
    } else {
        AlternativePaymentMethods()
    }
}

// Solution 2: Progressive loading with timeout
@Composable
fun GooglePayWithFallback(pxpCheckout: PxpCheckout) {
    var showGooglePay by remember { mutableStateOf(true) }
    var isLoading by remember { mutableStateOf(true) }
    
    LaunchedEffect(Unit) {
        withTimeoutOrNull(5000) {
            delay(100)
            isLoading = false
        }
        
        if (isLoading) {
            showGooglePay = false
            isLoading = false
        }
    }
    
    when {
        isLoading -> CircularProgressIndicator()
        showGooglePay -> GooglePayButton(pxpCheckout)
        else -> AlternativePaymentMethods()
    }
}

Payment sheet not opening

The symptoms of this are:

  • Button is visible and clickable but nothing happens.
  • No error messages are shown.
  • Payment sheet doesn't appear after button click.

Diagnostic steps

import android.util.Log
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.pxp.checkout.components.googlepay.*
import kotlinx.coroutines.CompletableDeferred

val config = GooglePayButtonComponentConfig().apply {
    onGooglePaymentButtonClicked = {
        Log.d("GooglePay", "Button clicked")
        Log.d("GooglePay", "Config: $paymentDataRequest")
        
        // Verify Google Play Services
        val googlePlayAvailable = GoogleApiAvailability.getInstance()
            .isGooglePlayServicesAvailable(context)
        
        if (googlePlayAvailable != ConnectionResult.SUCCESS) {
            Log.e("GooglePay", "Google Play Services unavailable: $googlePlayAvailable")
        }
        
        // Verify amount
        val amount = paymentDataRequest.transactionInfo.totalPrice.toDoubleOrNull()
        if (amount == null || amount <= 0) {
            Log.e("GooglePay", "Invalid amount: $amount")
        }
        
        CompletableDeferred(Unit)
    }
}

Solutions

import com.pxp.checkout.PxpCheckout
import com.pxp.checkout.components.googlepay.*
import kotlinx.coroutines.CompletableDeferred

// Solution 1: Add validation before opening sheet
val config = GooglePayButtonComponentConfig().apply {
    onGooglePaymentButtonClicked = {
        // Validate synchronously
        val email = getCustomerEmail()
        if (email.isEmpty() || !email.contains("@")) {
            showError("Please enter a valid email address")
            return@onGooglePaymentButtonClicked null
        }
        
        // Validate terms
        if (!areTermsAccepted()) {
            showError("Please accept terms and conditions")
            return@onGooglePaymentButtonClicked null
        }
        
        // Validate amount
        val amount = paymentDataRequest.transactionInfo.totalPrice.toDoubleOrNull()
        if (amount == null || amount <= 0) {
            showError("Invalid payment amount")
            return@onGooglePaymentButtonClicked null
        }
        
        // All validation passed
        CompletableDeferred(Unit)
    }
}

// Solution 2: Handle configuration errors
import android.util.Log
import com.pxp.checkout.PxpCheckout
import com.pxp.checkout.components.googlepay.*
import com.pxp.checkout.types.ComponentType

fun createGooglePayButton(pxpCheckout: PxpCheckout): GooglePayButtonComponent? {
    return try {
        validateGooglePayConfiguration(config)
        
        pxpCheckout.createComponent<GooglePayButtonComponent, GooglePayButtonComponentConfig>(
            type = ComponentType.GOOGLE_PAY_BUTTON,
            config = config
        )
    } catch (e: GooglePayConfigurationValidationFailedException) {
        Log.e("GooglePay", "Configuration validation failed", e)
        showError("Payment configuration error. Please contact support.")
        showAlternativePaymentMethods()
        null
    } catch (e: Exception) {
        Log.e("GooglePay", "Failed to create button", e)
        showError("Unable to initialise Google Pay. Please try again.")
        showAlternativePaymentMethods()
        null
    }
}

Payment authorisation failures

The symptoms of this are:

  • The Google Pay sheet appears but payment fails.
  • Customer sees a generic error message.
  • Transaction doesn't complete successfully.

Diagnostic steps

import android.util.Log
import com.pxp.checkout.PxpCheckout
import com.pxp.checkout.components.googlepay.*
import com.pxp.checkout.services.kount.*
import com.pxp.checkout.models.*
import kotlinx.coroutines.async

val config = GooglePayButtonComponentConfig().apply {
    onPreAuthorisation = suspend { data ->
        Log.d("GooglePay", "Pre-authorisation data: $data")
        Log.d("GooglePay", "Gateway token ID: ${data?.gatewayTokenId}")
        
        try {
            // Validate amount
            val amount = getOrderTotal()
            if (amount <= 0) {
                Log.e("GooglePay", "Invalid amount: $amount")
                throw IllegalStateException("Invalid transaction amount")
            }
            
            // Check inventory
            val inventoryAvailable = checkInventory()
            if (!inventoryAvailable) {
                Log.e("GooglePay", "Inventory not available")
                throw IllegalStateException("Items no longer available")
            }
            
            GooglePayTransactionInitData(
                riskScreeningData = RiskScreeningData(
                    performRiskScreening = true,
                    excludeDeviceData = false,
                    userIp = "192.168.1.100",
                    account = RiskScreeningAccount(
                        id = "user_12345678",
                        creationDateTime = "2024-01-15T10:30:00.000Z"
                    ),
                    fulfillments = listOf(
                        RiskScreeningFulfillment(
                            type = FulfillmentType.SHIPPED,
                            recipientPerson = RiskScreeningRecipientPerson(
                                phoneNumber = "+1234567890"
                            )
                        )
                    )
                )
            )
        } catch (e: Exception) {
            Log.e("GooglePay", "Pre-authorisation failed", e)
            null // Cancel payment
        }
    }
    
    onPostAuthorisation = { result, paymentData ->
        when (result) {
            is MerchantSubmitResult -> {
                Log.d("GooglePay", "Payment authorised: ${result.merchantTransactionId}")
            }
            is FailedSubmitResult -> {
                Log.e("GooglePay", "Payment failed: ${result.errorCode} - ${result.errorReason}")
            }
        }
    }
}

Solutions

import android.util.Log
import kotlinx.coroutines.delay

// Solution 1: Enhanced validation
fun validatePaymentData(paymentData: Any?): Boolean {
    require(paymentData != null) { "Payment data is missing" }
    
    val amount = getOrderTotal()
    require(amount > 0 && amount < 1000000) { "Invalid payment amount" }
    
    require(getCurrentCustomerEmail().isNotEmpty()) { "Customer email is required" }
    
    return true
}

// Solution 2: Implement retry logic
suspend fun processPaymentWithRetry(
    paymentData: Any,
    maxRetries: Int = 2
): PaymentResult {
    repeat(maxRetries) { attempt ->
        try {
            Log.d("Payment", "Payment attempt ${attempt + 1} of $maxRetries")
            return processPayment(paymentData)
        } catch (e: Exception) {
            Log.w("Payment", "Attempt ${attempt + 1} failed: ${e.message}")
            
            if (isRetryableError(e) && attempt < maxRetries - 1) {
                delay(1000L * (attempt + 1))
                continue
            }
            throw e
        }
    }
    throw IllegalStateException("Payment retry logic failed")
}

fun isRetryableError(error: Exception): Boolean {
    val retryableErrors = listOf("network error", "timeout", "temporary failure")
    return retryableErrors.any { error.message?.lowercase()?.contains(it) == true }
}

Debugging tools and techniques

Logging setup

import android.content.Context
import android.util.Log
import android.os.Build
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.pxp.checkout.components.googlepay.*

// Log environment information
fun logGooglePayEnvironment(context: Context) {
    Log.d("GooglePay", "=== Environment ===")
    Log.d("GooglePay", "Device: ${Build.MANUFACTURER} ${Build.MODEL}")
    Log.d("GooglePay", "Android: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT})")
    
    val googlePlayAvailable = GoogleApiAvailability.getInstance()
        .isGooglePlayServicesAvailable(context)
    Log.d("GooglePay", "Google Play Services: $googlePlayAvailable")
}

// Log configuration
fun logGooglePayConfig(config: GooglePayButtonComponentConfig) {
    Log.d("GooglePay", "=== Configuration ===")
    val method = config.paymentDataRequest.allowedPaymentMethods.firstOrNull()
    Log.d("GooglePay", "Card networks: ${method?.parameters?.allowedCardNetworks}")
    Log.d("GooglePay", "Auth methods: ${method?.parameters?.allowedAuthMethods}")
    Log.d("GooglePay", "Amount: ${config.paymentDataRequest.transactionInfo.totalPrice}")
    Log.d("GooglePay", "Currency: ${config.paymentDataRequest.transactionInfo.currencyCode}")
}

Logcat filtering

Filter Logcat for Google Pay related logs:

adb logcat | grep -E "GooglePay|PxpCheckout"

Android Studio Profiler

Use Android Studio's built-in profilers to monitor performance, memory usage, and network calls during payment processing.

Prevention and best practices

Pre-flight checks

Perform checks before initialising Google Pay to catch issues early:

import android.accounts.AccountManager
import android.content.Context
import android.os.Build
import android.util.Log
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability

fun performPreflightChecks(context: Context): Boolean {
    // Check Google Play Services
    val googlePlayResult = GoogleApiAvailability.getInstance()
        .isGooglePlayServicesAvailable(context)
    if (googlePlayResult != ConnectionResult.SUCCESS) {
        Log.w("GooglePay", "Google Play Services unavailable")
        return false
    }
    
    // Check Android version
    if (Build.VERSION.SDK_INT < 24) {
        Log.w("GooglePay", "Android version too low")
        return false
    }
    
    // Check Google account
    val accountManager = AccountManager.get(context)
    if (accountManager.getAccountsByType("com.google").isEmpty()) {
        Log.w("GooglePay", "No Google account")
        return false
    }
    
    // Check payment configuration
    val config = getGooglePayConfig()
    if (config.paymentDataRequest.allowedPaymentMethods.isEmpty()) {
        Log.w("GooglePay", "No payment methods configured")
        return false
    }
    
    return true
}

// Use before initialisation
import androidx.compose.runtime.*
import com.pxp.checkout.PxpCheckout

@Composable
fun SafeGooglePayButton(pxpCheckout: PxpCheckout) {
    val isAvailable = remember {
        performPreflightChecks(context)
    }
    
    if (isAvailable) {
        GooglePayButton(pxpCheckout)
    } else {
        AlternativePaymentMethods()
    }
}

Error monitoring

Track errors using your preferred monitoring service:

import android.util.Log
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.pxp.checkout.components.googlepay.*
import com.pxp.checkout.models.*

val config = GooglePayButtonComponentConfig().apply {
    onError = { error ->
        // Log to your monitoring service (e.g., Firebase Crashlytics, Sentry)
        FirebaseCrashlytics.getInstance().apply {
            setCustomKey("component", "GooglePay")
            setCustomKey("error_type", error::class.simpleName ?: "Unknown")
            recordException(error)
        }
        
        // Show user-friendly message
        showErrorMessage(error)
    }
    
    onPostAuthorisation = { result, _ ->
        when (result) {
            is MerchantSubmitResult -> {
                Log.d("GooglePay", "Payment successful: ${result.merchantTransactionId}")
            }
            is FailedSubmitResult -> {
                Log.e("GooglePay", "Payment failed: ${result.errorCode}")
            }
        }
    }
}