> ## Documentation Index
> Fetch the complete documentation index at: https://docs.verifyyou.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> What onError fires with, and how React Native's promise reflects it.

`onError` fires when a run never reaches a settled outcome at all. This is distinct from `onClose`, which means the person dismissed a run that did open. Every message today is a plain string. There is no error code to branch on.

<CodeGroup>
  ```kotlin Android theme={null}
  VerifyYou.vycheck(
      context = this,
      session = sessionId,
      onComplete = { result -> /* ... */ },
      onError = { message ->
          // An empty session, a run already in progress, or the hosted
          // page failed to load or start. Mint a fresh session and let them retry.
          Log.e("MyApp", "verifyyou: $message")
      },
  )
  ```

  ```swift iOS theme={null}
  VerifyYou.vycheck(
      from: self,
      session: sessionId,
      onComplete: { result in /* ... */ },
      onError: { message in
          // An empty session, a run already in progress, or the hosted
          // page failed to load or start. Mint a fresh session and let them retry.
          print("verifyyou:", message)
      }
  )
  ```

  ```ts React Native theme={null}
  try {
    const { token } = await vycheck({ session: sessionId });
    if (!token) {
      // They closed it without finishing. Not an error. Let them retry.
    }
  } catch (err) {
    // An empty session, a run already in progress, or the hosted page
    // failed to load or start. Mint a fresh session and let them retry.
    const message = err instanceof Error ? err.message : String(err);
    console.error("verifyyou:", message);
  }
  ```
</CodeGroup>

## When it fires

| Cause | Message names |
| - | - |
| `session` is empty or blank | that it must not be empty |
| A run is already presenting | that a verification is already in progress |
| `appBase` produced an unbuildable URL | that the hosted URL failed to build |
| The hosted page failed to load, answered with an HTTP error, or its WebView crashed | that the page failed to load, returned an error, or crashed |
| The hosted flow did not load within 20 seconds of the `vycheck()` call | `the verification page did not start` |
| The device's WebView is too old (Android only) | `this device's WebView is too old to run verification` |
| The verification screen did not open. On Android, the system refused to start it. On iOS, the screen you passed as `from` is not on screen, or is being dismissed. | `could not open the verification screen` |

The Android only row also reaches a React Native app running on Android.

An empty session reports an error. A bad, expired or already used session does not. The web SDK makes no network call when it opens a session by id, so nothing rejects at call time. The problem shows up on the hosted page itself, inside the screen. The person can close that screen, which calls `onClose`.

The flow itself runs on the [browser SDK](/v3/dev/spec/browser-sdk/errors) inside the native screen, so anything the browser SDK rejects with reaches `onError` with the same message.

## Dismissal is not an error

Closing the screen without finishing calls `onClose`, or on React Native resolves the promise with `{ token: null, verified: false, vyc: null }`. Look for a missing `token` instead. Do not treat this as a rejection.

## React Native: onError and the promise both fire

A native error calls `onError` and rejects the returned promise with a real `Error`, so `err.message` reads the same string `onError` receives. Use whichever fits your code: the callback for a component that never awaits the handle, `catch` for one that does.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.