Handle Firebase Phone Number Verification errors on Android

When a call to the Firebase PNV library fails, the library reports a FirebasePhoneNumberVerificationException. This page lists every error code that the exception can carry, when each one occurs, and what your app should do about it.

This page assumes you've integrated Firebase PNV as described in Get started with Firebase Phone Number Verification on Android.

How errors are reported

  • Asynchronous methods (getVerificationSupportInfo(), getVerifiedPhoneNumber(), and the custom flow methods) return a Task. When they fail, the Task fails with a FirebasePhoneNumberVerificationException, which you receive in addOnFailureListener.

  • enableTestSession() is synchronous. It throws a FirebasePhoneNumberVerificationException directly.

Read the exception's errorCode to find out what went wrong. The Firebase PNV codes are constants in the FirebasePnvStatusCodes class. If the failure comes from Google Play services, errorCode can also be a CommonStatusCodes value, such as NETWORK_ERROR.

An unsupported device or SIM isn't an error. getVerificationSupportInfo() succeeds and reports isSupported() as false for that SIM, and getReason() tells you why. See Unsupported devices and SIMs.

Error codes

Test session setup

These errors are thrown synchronously by enableTestSession().

Error code Cause Recommended action
TEST_SESSION_ALREADY_ENABLED
(55508)
enableTestSession() was called more than once in the same app process. FirebasePhoneNumberVerification.getInstance() returns the same instance every time, so this also happens when an Activity that calls it is recreated. Call enableTestSession() once per process, for example in Application.onCreate(). See Initialize the library in test mode.
INVALID_TEST_NUMBER_ID
(55507)
The test token passed to enableTestSession() is empty. Make sure your build passes the token you generated in the Firebase console, and only call enableTestSession() when the token isn't empty.

Verification

These errors fail the Task returned by getVerifiedPhoneNumber().

Error code Cause Recommended action
CREDENTIAL_MANAGER_ERROR
(55506)
Android Credential Manager didn't return the phone number. If the exception's cause is a GetCredentialCancellationException, the user most likely dismissed the consent screen. Offer another way to verify the phone number, such as SMS. Don't retry automatically, because the user would see the consent screen again.
CARRIER_NOT_SUPPORTED
(55501)
The carrier of the selected SIM isn't supported, or the device doesn't have the subscription information needed to verify it. Fall back to another verification method, such as SMS.
UNSUPPORTED_OPERATION
(55505)
Firebase PNV isn't available for this request on the device. Fall back to another verification method, such as SMS.
PREFLIGHT_CHECK_FAILED
(55504)
The Firebase PNV backend couldn't create the verification request, before the consent screen was shown. Fall back to another verification method, such as SMS. If it happens for every request, check that your app is set up correctly (see Upgrade to production mode).
INTEGRITY_CHECK_FAILED
(55503)
The device or app failed an integrity check. Fall back to another verification method, such as SMS.
INVALID_DIGITAL_CREDENTIAL_RESPONSE
(55502)
The response from Credential Manager couldn't be read, or couldn't be exchanged for a verified phone number. Fall back to another verification method, such as SMS.
INVALID_TEST_NUMBER_ID
(55507)
In test mode, the Firebase PNV backend rejected the test token, for example because it expired. Test tokens have a 7 day TTL. A rejected test token usually reports this code; if you see other errors in test mode, also check that your token is current. Generate a new test token in the Firebase console and rebuild your app.
ACTIVITY_CONTEXT_REQUIRED
(55509)
The Context passed to getVerifiedPhoneNumber() isn't an Activity. The method needs an Activity to show the consent screen. Pass the current Activity. This is a bug in your app, not a condition to handle at runtime.

Support check

The Task returned by getVerificationSupportInfo() fails only if the check itself can't run. In that case, errorCode is either a Google Play services CommonStatusCodes value or CARRIER_NOT_SUPPORTED. Treat the device as unsupported and fall back to another verification method, such as SMS.

While a test session is enabled, getVerificationSupportInfo() doesn't contact the Firebase PNV backend and always reports the test SIM as supported, even if the test token has expired.

Custom flow

If you use the custom flow instead of getVerifiedPhoneNumber():

  • getDigitalCredentialPayload() fails with PREFLIGHT_CHECK_FAILED, or with INVALID_TEST_NUMBER_ID if the backend rejects your test token.
  • exchangeCredentialResponseForPhoneNumber() fails with INVALID_DIGITAL_CREDENTIAL_RESPONSE, or with INVALID_TEST_NUMBER_ID if the backend rejects your test token.
  • Your own call to Credential Manager throws a GetCredentialException, which you handle directly.

Unsupported devices and SIMs

When isSupported() is false for a SIM, getReason() returns one of the following VerificationSupportStatus values:

Value Meaning
INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED The SIM's carrier isn't supported. See Supported carriers.
INCAPABLE_DUE_TO_ANDROID_VERSION The device runs a version of Android older than Android 9 (API level 28).
INCAPABLE_DUE_TO_SIM_STATE The SIM isn't ready. A SIM that is locked or still loading can also report INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED, because the carrier is checked first.

In each case, use another verification method, such as SMS, for that SIM.

Example

The following example handles the errors that a typical app needs to distinguish when calling getVerifiedPhoneNumber():

Kotlin

import android.util.Log
// Credential Manager is included with the Firebase PNV library.
import androidx.credentials.exceptions.GetCredentialCancellationException
import com.google.firebase.pnv.FirebasePhoneNumberVerification
import com.google.firebase.pnv.FirebasePhoneNumberVerificationException
import com.google.firebase.pnv.FirebasePnvStatusCodes

private const val TAG = "PhoneVerification"

// In your Activity:
private fun verifyPhoneNumber() {
    FirebasePhoneNumberVerification.getInstance()
        .getVerifiedPhoneNumber(this)
        .addOnSuccessListener { result ->
            // Send result.getToken() to your backend.
        }
        .addOnFailureListener { e -> handleFpnvError(e) }
}

private fun handleFpnvError(e: Exception) {
    if (e !is FirebasePhoneNumberVerificationException) {
        Log.w(TAG, "Firebase PNV failed", e)
        showSmsVerification()
        return
    }
    when (e.errorCode) {
        FirebasePnvStatusCodes.CREDENTIAL_MANAGER_ERROR -> {
            if (e.cause is GetCredentialCancellationException) {
                // The user dismissed the consent screen.
            }
            showSmsVerification()
        }
        FirebasePnvStatusCodes.INVALID_TEST_NUMBER_ID -> {
            // Test mode only: generate a new test token.
            Log.e(TAG, "Firebase PNV test token rejected", e)
        }
        FirebasePnvStatusCodes.ACTIVITY_CONTEXT_REQUIRED -> {
            // App bug: pass an Activity to getVerifiedPhoneNumber().
            Log.e(TAG, "Firebase PNV needs an Activity context", e)
        }
        else -> {
            // Carrier not supported, network errors, and other failures.
            Log.w(TAG, "Firebase PNV failed with error code ${e.errorCode}", e)
            showSmsVerification()
        }
    }
}

In this example, showSmsVerification() is your app's existing phone number verification flow.

Next steps