Troubleshooting
Common issues and their solutions when integrating the Payrails Android SDK.
Build Issues
"Payrails session must be initialized"
Error: IllegalStateException: Payrails session must be initialized
Cause: You called createCardForm(), createCardPaymentButton(), or createStoredInstruments() before Payrails.createSession().
Fix: Ensure createSession() completes successfully before creating any UI elements:
// Correct order
val session = Payrails.createSession(configuration) // must complete first
val cardForm = Payrails.createCardForm() // now safe
val payButton = Payrails.createCardPaymentButton(...) // now safeMissing CSE Dependency
Error: Runtime crash or NoClassDefFoundError related to card encryption
Fix: Add both dependencies:
dependencies {
implementation("com.payrails.checkout:android-sdk:<version>")
implementation("com.payrails.android:cse:<version>") // required for card payments
}Card Form Issues
Card Form Not Validating
Symptom: User can submit without validation, or errors don't show.
Checks:
- The
CardPaymentButtonvalidates the form automatically when clicked. You don't need to callvalidate()manually. - Validation errors appear after the user taps "Pay Now" or when a field loses focus (blur validation).
- If you're using
onChangeevents, checkevent.isValidfor real-time validation state.
Card Network Not Detected
Symptom: cardNetwork stays UNKNOWN, card icon doesn't update.
Checks:
- Network detection requires at least 1–2 digits. Enter a full card number to see detection.
- Supported networks: Visa, Mastercard, Amex, Discover. Other networks show as
UNKNOWN. - Ensure
showCardIcon = trueinCardFormConfigif you expect to see icons.
Layout Crashes at Creation
Error: IllegalArgumentException: CardForm layout contains unsupported fields or similar.
Fix: Check your layout configuration:
- Don't mix
EXPIRATION_DATEwithEXPIRATION_MONTH/EXPIRATION_YEAR - Don't duplicate fields across rows
- Supported fields:
CARDHOLDER_NAME,CARD_NUMBER,EXPIRATION_DATE,EXPIRATION_MONTH,EXPIRATION_YEAR,CVV
Payment Issues
3DS Browser Doesn't Open
Symptom: Payment hangs after authorization, no browser opens.
Checks:
- Ensure a
PaymentPresenteris set on the button:payButton.presenter = presenter - If you don't set one, the SDK creates a default browser presenter automatically, but only after
Render()is composed - The device must have a browser installed (Chrome Custom Tabs preferred)
- Check that the Activity reference is still valid (not destroyed)
3DS Succeeds But onAuthorizeSuccess Not Called
Symptom: User completes 3DS in browser, returns to app, but delegate isn't called.
Explanation: This is expected behavior. The SDK polls the execution status after the user returns. The delegate callback fires only when polling reaches a terminal state (success or failure).
Possible causes for delay:
- Slow backend processing — the SDK continues polling
- Network connectivity issues — polling retries with backoff
- If polling times out,
onAuthorizeFailedfires instead (the SDK triggers session recovery ifonSessionExpiredis configured)
Payment Always Returns authorizationFailed
Checks:
- Verify your init payload is correct (version and data from your backend)
- Check that your Payrails dashboard has the payment method configured
- Ensure your test card numbers are valid for your sandbox environment
- Look at
PayrailsErrorin theonAuthorizationFailedcase for specific details
Stored Instrument Payment Fails
Checks:
- Ensure the stored instrument is still valid (not expired or deleted)
- Set the presenter on the button:
payButton.presenter = presenter - Verify the instrument was retrieved from the current session:
Payrails.getStoredInstruments()
Lifecycle Issues
Session Lost After Configuration Change
Symptom: Payment fails after screen rotation or configuration change.
Explanation: The SDK ties the session to the Activity lifecycle. When the Activity is destroyed (including for configuration changes), the session is cleaned up if isFinishing is true.
Fix: For configuration changes (rotation), the standard Compose remember pattern preserves element references across recomposition. However, if the Activity is recreated, you'll need to re-initialize the session.
Consider using a ViewModel to hold the session across configuration changes:
class PaymentViewModel : ViewModel() {
var session: Session? = null
private set
suspend fun initializeSession(configuration: Configuration) {
session = Payrails.createSession(configuration)
}
}Memory Leak Warnings
Symptom: LeakCanary reports a leak from Payrails or BrowserPaymentPresenterImpl.
Checks:
- The SDK holds a
WeakReferenceto the Activity — this should not cause leaks - Ensure you're not holding strong references to
CardFormorCardPaymentButtonin long-lived scopes (e.g., a singleton) - The SDK registers
ActivityLifecycleCallbacksonce and cleans up when the bound Activity is destroyed
ProGuard / R8
If you're using code shrinking, the SDK's public API should work without additional rules. If you encounter issues with serialization or reflection:
-keep class com.payrails.sdk.** { *; }This is a broad keep rule. In most cases, the SDK works without any ProGuard configuration. Only add rules if you see specific obfuscation-related crashes.
Getting Help
If your issue isn't covered here:
- Review the SDK Concepts to verify your integration pattern
- Check the API Reference for correct method signatures
- Contact Payrails support with:
- SDK version
- Android API level
- The specific
PayrailsErrormessage (if applicable) - Steps to reproduce
Updated about 14 hours ago