PingOne Recognize

Error Handling

The PingOne Recognize SDK uses three classes of errors. Each error has an error code and an error message:

  • User errors: triggered by unintended or suspicious user behavior (30_000 and above).

  • Integration errors: triggered by a PingOne Recognize SDK integration misconfiguration (20_000 to 30_000).

  • Internal errors: triggered by PingOne Recognize internals (below 20_000).

If you are implementing the PingOne Recognize SDK, handle errors coming from the SDK because the raw error message is not intended for end users.

User Errors

User errors have codes 30_000 and above.

Many of these errors are predictions only. When writing messages for users, it is often best to assume positive intent. For example, suggest checking whether anything is obstructing the camera instead of suggesting spoofing.

Error Code Description Recommendations

Genuine presence not established

30000

The user’s genuine presence cannot be established.

The user might be placing a picture or a video in front of the camera. Our system is probabilistic, upon failure, advise users to ensure their face is well-lit and fully visible before retrying. The user can utilize live feedback during the camera scan for real-time guidance.

Timeout

30001

The face could not be recognized before the specified timeout.

Note: This error is no longer returned from SDK version 5.0.1 and above because the liveness timeout feature was deprecated. See changelog details.

The user can retry placing the face in front of the camera as soon as the camera opens.

Mask detected

30002

The user might be wearing a mask, or something might be hiding their face.

Note: Mask detected is part of live feedback and is no longer returned as an error from SDK version 4.8.0 and above.

It is very likely that there is some occlusion on the face. We advise to retry and utilize the live feedback during the camera scan for real-time guidance.

User cancelled

30003

The user manually cancelled face recognition or image processing.

This error occurs when the user cancels the face scan with the back button. We recommend either suppressing the error (the event is logged internally for debugging) or prompting the user to retry in case the cancellation was accidental.

Face not matching

30004

The face of the user in front of the camera doesn’t match the face currently enrolled with PingOne Recognize.

This indicates a biometric mismatch: a face was detected, but it does not match the enrolled profile. We recommend prompting a retry or advising the user to verify they have selected the correct account.

No network connection

30005

The device appears to be offline.

This error indicates a loss of network connectivity. We recommend prompting the user to verify their internet connection and restart the scan. If the issue persists, advise them to wait a few minutes before retrying.

Device tampered

30006

The device seems tampered and could have been rooted or jailbroken. Note: This error has been superseded by runtime application self protection.

This error suggests that the device is likely rooted or jailbroken. Advise the user to try on another device. If not possible reach out to Keyless support for further guidance.

User lockout

30007

The user is temporarily locked out of PingOne Recognize after too many failed authentication attempts. Note: For new device activation, a different lockout code 523 is returned.

We advise the user to wait for the indicated time. We advise to expose to the user a functionality to check the remaining time from the app before retrying. The customer can use the APIs in the Lockout management section.

Rejected

30008

PingOne Recognize did not manage to recognize the user but does not suspect any spoofing attempt.

The model is not providing further hints on the issue. We advise users to utilize the live feedback during the camera scan for real-time guidance.

Camera permission denied

30009

The user denied camera permission.

We advise the customer app to ensure camera permissions are granted. If needed, prepare an informative screen on why the camera permissions are necessary to perform the face scan.

Outdated app

30010

The app is using a mobile SDK version that is too old to be compatible with our backend.

We advise to update to a more recent mobile SDK.

Integration Errors

Integration errors have codes from 20_000 to 30_000.

Integration errors can be solved by ensuring the SDK API surface is used correctly. If errors persist, keep the error code, message, and stack trace, then contact support.

Error Code Description Recommendations

User Not Enrolled

20000

The user is not enrolled and you are likely trying to authenticate the user. It is necessary to enroll the user first.

We advise to verify that the user is not enrolled before calling Keyless.authenticate using the method validateUserAndDeviceActive from user and device management.

User Already Enrolled

20001

You are likely trying to enroll the user, but there is an already enrolled user on the device.

If you need to enroll a new user call reset before calling Keyless.enroll. It is possible to verify if the user is enrolled using the method validateUserAndDeviceActive from user and device management.

SDK not configured

20002

There was an error when calling Keyless.configure. Note: From SDK version 6.0.0 and above you can use the debuggingInfo field in the returned error object to verify the internal reason causing the SDK misconfiguration.

You are likely trying to start an enrollment or an authentication flow without the SDK being properly configured.

Legacy SDK configure failed

20005

This error should no longer be returned and has been replaced by the error 20010.

Refer to 20010.

SDK invalid configuration

20010

There was an error when calling Keyless.configure. Note: From SDK version 6.0.0 and above you can use the debuggingInfo field in the returned error object to verify the internal reason causing the SDK misconfiguration.

This error typically occurs due to misconfigured tenant feature flags or a failure to reach the feature flag service during SDK setup. In rare cases, it may also be caused by insufficient device storage preventing the SDK from writing necessary local files.

Not enough API key seats

20013

The license of the mobile SDK cannot enroll users anymore.

It is likely that you had a limit on users when purchasing the mobile SDK, reach out to support to verify available seats.

Liveness Environment Aware

20021

The device does not meet the requirements for environment-aware liveness detection. Note: From SDK version 6.0.0 and above, the liveness environment aware check will be managed internally in the SDK.

We advise the customer to turn-off the liveness environment aware feature if this creates frictions for the users.

Device Environment Aware

20022

The device does not meet the requirements for liveness to start.

Reach out to support to disable the feature. We do not expect this to happen often, should have less friction than Liveness Environment Aware.

Invalid client state

20023

The client state you are using is likely no longer valid.

This can happen if the original user for which the client state was generated has been de-enrolled. We advise to generate a new client state for that user.

Dynamic linking malformed payload

20150

You are trying to use the dynamic linking feature passing a payload that does not conform to the expected one.

See dynamic linking guide.

Secret not found

20300

You are trying to retrieve a secret using a secret identifier that was not stored in the mobile SDK.

Ensure the secret identifier was set, see secret management.

Internal Errors

All errors below 20_000 are internal errors and relate to responses from the core platform. These typically require PingOne Recognize support investigation, though some can be actioned by integrators.

Error Code Description Recommendation

PROTOCOL_INVALID_MESSAGE

507

Client-server mismatch suggesting an issue communicating with the Core backend.

This could be due to network drop, or an outdated (unsupported) core client trying to contact the latest core backend.

PROTOCOL_FAILED_TO_AUTHENTICATE_USER

512

The given user selfie did not meet the threshold of an approved match. In simple terms, confidence was not high enough that this was the same face registered to this PingOne Recognize ID.

In most cases, advise positive intent and ask the user to retry in a well-lit environment, with face centered and nothing covering the face. Integrators should also consider that this can occur when the person attempting authentication is not the registered person.

PROTOCOL_NO_SUCH_CIRCUIT_ID

514

The core backend and core client cannot agree on the selected circuit. This can be caused by the local storage synchronization failures.

We advise to retry the authentication, if enough circuits are available sync should be fixed with further authentications. If the issue persists, we advise to enroll the user anew.

PROTOCOL_BAD_REQUEST

537

Core backend returned a 400 HTTP status error.

We advise to retry the operation. If the issue persists prompt the user to wait a few minutes before retrying. Lastly, if the user still sees the same error we advise to enroll the user anew.

PROTOCOL_MAX_NUMBER_OF_DEVICES_REACHED

539

The maximum number of devices has been reached. Maximum is 50 devices per PingOne Recognize ID. These may include backup or temporary client states, not only physical devices.

Revoke existing states/devices to generate new ones. For SaaS customers, this can be done in PingOne Recognize dashboard or through the Server API .

NET_CONNECTION_FAILED

1004

Network unavailable or server response unexpected.

If networking is available, refer to 507.

CLIENT_INVALID_INPUT

1134

Incorrect or invalid parameter passed to a core function.

This may be solved by re-running the PingOne Recognize enrollment or authentication request. Alternatively, SDK/core client sync may be corrupted.

CLIENT_UNKNOWN_ERROR

1142

The local state of the Keyless SDK - core client - might not be in sync with the core backend.

This may happen also in case the device time is not set correctly. We advise to ensure the device is genuine and has a correct time setting. If the issue persists, we advise to enroll the user anew.

CLIENT_AUTH_METHOD_NOT_ENABLED

1167

It is possible that you are trying to authenticate the user with the PIN but the PIN was never set for that user.

We advise to ensure that the pin authentication factor is enabled and has been set for the user.

CLIENT_ALREADY_ENROLLED

1124

Legacy: should be re-mapped to 20001.

Refer to 20001.

SdkGeneric

10000

We cannot establish the exact error.

Note: From SDK version 6.0.0 and above you can use the debuggingInfo field in the returned error object to verify the internal reason.

UnableToRetrieveRequiredArtifact

10001

The user was enrolled with a model that is no longer available on the device.

This can be caused by a partial app update where the mobile SDK could not update the model before enrolling the user. Try to configure the SDK again, if the issue persists use the debuggingInfo field in the returned error object to verify the internal reason.

LoggingConfigurationFailed

10003

It is not possible to configure the KeylessLogsConfiguration. Learn more in logging.

We advise to make sure there was no connectivity drop during the setup and retry again to call Keyless.configure.

FrameProviderConfigurationFailed

10004

We are not able to retrieve camera frames.

Use the debuggingInfo field in the returned error object to verify the internal reason.

StorageFailed

10005

We are not able to copy files for the correct functioning of the SDK.

Ensure the user has enough space on the device (at least 50Mb). If the issue persists use the debuggingInfo field in the returned error object to verify the internal reason.

InvalidCustomerProperties

10006

Our feature flagging system returned an invalid configuration.

Retry to configure the SDK. If the issue persists use the debuggingInfo field in the returned error object to verify the internal reason.

BiomGeneric

10100

There is an issue with the biometric library.

Retry the enrollment/authentication flow. If the issue persists use the debuggingInfo field in the returned error object to verify the internal reason.

CoreGeneric

10200

There is an issue with the core library.

Retry the enrollment/authentication flow. If the issue persists use the debuggingInfo field in the returned error object to verify the internal reason.

If errors in this range persist and are unclear, keep the error code, error message, and stack trace and contact support. If possible, enable PingOne Recognize logging at TRACE level and share those logs to speed investigation.

Anti-Inject Errors

The following errors apply to PingOne Recognize Anti-Inject variant only.

Error Code Description

Anti-inject initialization failed

40000

(PingOne Recognize Anti-Inject variant only.) Initialization of Anti-Inject failed for an internal error.

License expired

40001

(PingOne Recognize Anti-Inject variant only.) The license configFile.tak is expired. Contact PingOne Recognize team for an updated license.

Device might not be genuine

40002

(PingOne Recognize Anti-Inject variant only.) Signals indicate this device may be compromised or not genuine. This prevents the user from continuing and enrollment/authentication is not possible.

Examples

Android

val configuration = Keyless.AuthenticationConfiguration()

Keyless.authenticate(
    authenticationConfiguration = configuration,
    onCompletion = { result ->
        when (result) {
            is Keyless.KeylessResult.Success -> {
                Log.d("IntegratorActivity ", "Authenticate success")
            }
            is Keyless.KeylessResult.Failure -> {
                when (result.error) {
                    is KeylessUserError.GenuinePresenceNotEstablished -> Log.d("IntegratorActivity ", "Cannot establish genuine presence")
                    is KeylessUserError.FaceNotMatching -> Log.d("IntegratorActivity ", "Face not matching")
                    is KeylessUserError.UserCancelled -> Log.d("IntegratorActivity ", "The user cancelled the operation")
                    is KeylessUserError.NoNetworkConnection -> Log.d("IntegratorActivity ", "No network connection available")
                    is KeylessUserError.Lockout -> Log.d("IntegratorActivity ", "Your account is temporarily locked")
                    else -> {
                        Log.d("IntegratorActivity ", "Authenticate failure")

                        val errorCode = result.error.code
                        val errorMessage = result.error.message
                        // display a generic error popup for the user + use debuggingInfo for troubleshooting
                    }
                }
            }
        }
    }
)

iOS

let configuration = Keyless.AuthenticationConfiguration.builder.build()

Keyless.authenticate(authenticationConfiguration: configuration) { result in
    switch result {
    case .success(let authenticationSuccess):
        print("authenticationDidFinish:  \(authenticationSuccess.token)")
    case .failure(let error):
        switch error.kind {
        case .userError(let userError):
            switch userError {
            case .genuinePresenceNotEstablished:
                print("Cannot establish genuine presence")
            case .faceNotMatching:
                print("Face not matching")
            case .userCancelled:
                print("The user cancelled the operation")
            case .noNetworkConnection:
                print("No network connection available")
            case .lockout:
                print("Your account is temporarily locked")
            }
        default:
            let code = error.code
            let message = error.message
            // display a generic error popup with the error code
        }
    }
}

Flutter

import 'package:keyless_flutter_sdk/keyless.dart';
import 'package:keyless_flutter_sdk/models/configurations/authentication_configuration.dart';

final configuration = BiomAuthConfig();

try {
  final result = await Keyless.instance.authenticate(configuration);
  print("Authentication successful");
} catch (error) {
  if (error is KeylessError) {
    switch (error.errorType) {
      case KeylessErrorType.user:
        if (error.code == KeylessErrorCase.faceNotMatching.code) {
          print("Face not matching");
        } else if (error.code == KeylessErrorCase.maskDetected.code) {
          print("Mask detected");
        } else if (error.code == KeylessErrorCase.spoofing.code) {
          print("Spoofing detected");
        } else if (error.code == KeylessErrorCase.timeout.code) {
          print("The operation timed out");
        } else if (error.code == KeylessErrorCase.userCancelled.code) {
          print("The user cancelled the operation");
        } else if (error.code == KeylessErrorCase.noNetworkConnection.code) {
          print("No network connection available");
        } else if (error.code == KeylessErrorCase.deviceTampered.code) {
          print("Device security check failed");
        } else if (error.code == KeylessErrorCase.lockout.code) {
          print("Your account is temporarily locked");
        }
        break;
      default:
        print("Authentication failed: ${error.message} (Code: ${error.code})");
    }
  }
}