When a call to the Firebase PNV library fails, the library reports a
[`FirebasePhoneNumberVerificationException`](https://firebase.google.com/docs/reference/android/com/google/firebase/pnv/FirebasePhoneNumberVerificationException.md.txt).
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](https://firebase.google.com/docs/phone-number-verification/android/get-started.md.txt).

## How errors are reported

- **Asynchronous methods** (`getVerificationSupportInfo()`,
  `getVerifiedPhoneNumber()`, and the [custom flow](https://firebase.google.com/docs/phone-number-verification/android/custom-flow.md.txt) 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`](https://firebase.google.com/docs/reference/android/com/google/firebase/pnv/FirebasePnvStatusCodes.md.txt)
class. If the failure comes from Google Play services, `errorCode` can also be a
[`CommonStatusCodes`](https://developers.google.com/android/reference/com/google/android/gms/common/api/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](https://firebase.google.com/docs/phone-number-verification/android/handle-errors.md.txt#unsupported).

## 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](https://firebase.google.com/docs/phone-number-verification/android/get-started.md.txt#test-token). |
| `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](https://firebase.google.com/docs/phone-number-verification/android/production-mode.md.txt)). |
| `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](https://firebase.google.com/docs/phone-number-verification/android/custom-flow.md.txt) 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`](https://firebase.google.com/docs/reference/android/com/google/firebase/pnv/VerificationSupportStatus.md.txt)
values:

| Value | Meaning |
|---|---|
| `INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED` | The SIM's carrier isn't supported. See [Supported carriers](https://firebase.google.com/docs/phone-number-verification/pricing.md.txt#supported-carriers). |
| `INCAPABLE_DUE_TO_ANDROID_VERSION` | The device runs a version of Android older than Android 10 (API level 29). |
| `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

```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

- For details about each class and constant, see the [Firebase PNV API reference](https://firebase.google.com/docs/reference/kotlin/com/google/firebase/pnv/package-summary.md.txt).
- To verify the token on your server, see [Verify Firebase PNV tokens](https://firebase.google.com/docs/phone-number-verification/verify-tokens.md.txt).