Learn how to diagnose and fix common issues with the Google Pay Android component.
The Google Pay Android component throws specific exceptions for different error scenarios:
| Exception | Error code | Description |
|---|---|---|
GooglePayLoadFailedException | SDK0704 | The Google Pay API failed to load. For example, due to network issues, Google Play Services unavailable, or device incompatibility. |
GooglePayNotReadyException | SDK0701 | Google Pay isn't ready on this device. For example, Google Play Services not installed, no Google account, or no payment methods configured. |
GooglePayClientNotInitializedException | SDK0703 | The Google Pay client was not properly initialised before attempting a payment. |
GooglePayConfigurationValidationFailedException | SDK0705 | Configuration validation failed. For example, missing required fields, invalid payment method configuration, or incorrect format. |
GooglePayPaymentFailedException | SDK0702 | Payment processing failed. For example, due to network issues, declined payment, or server errors. |
GooglePayDecryptAndTokenVaultFailedException | SDK0706 | Payment token decryption or vault storage failed. Check gateway configuration and token handling. |
UnsupportedFundingTypeGooglePaySdkException | SDK0108 | Google 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.
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")
}
}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.
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
}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()
}
}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.
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)
}
}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
}
}The symptoms of this are:
- The Google Pay sheet appears but payment fails.
- Customer sees a generic error message.
- Transaction doesn't complete successfully.
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}")
}
}
}
}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 }
}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}")
}Filter Logcat for Google Pay related logs:
adb logcat | grep -E "GooglePay|PxpCheckout"Use Android Studio's built-in profilers to monitor performance, memory usage, and network calls during payment processing.
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()
}
}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}")
}
}
}
}