# Error Handling

This section helps with handling Offline Navigation failures with stable error codes instead of diagnostic message text and converting callback errors, choosing safe retry behavior, and initiating recovery after checking current state, network policy, storage, and lifecycle ownership.

Normally, `NBNavigation` reports failures through _NBNavigationApiException_. Convert any callback “Throwable” with `toNavigationError()`, branch on the stable `NBNavigationErrorCode` enum, and retain `causeCode` for diagnostics. Do not use message or `causeDescription` as a business-logic condition.

```kotlin
private fun recoveryMessage(throwable: Throwable): String {
    val error = NBNavigation.toNavigationError(throwable)
    return when (error.code) {
        NBNavigationErrorCode.INVALID_ARGUMENT ->
            "Check the request parameters; do not retry unchanged input."
        NBNavigationErrorCode.NETWORK_UNAVAILABLE ->
            "Wait until the configured network policy is satisfied."
        NBNavigationErrorCode.TIMEOUT ->
            "Retry with bounded exponential backoff."
        NBNavigationErrorCode.OFFLINE_DATA_NOT_READY,
        NBNavigationErrorCode.OFFLINE_DATA_VERSION_MISMATCH ->
            "Synchronize the catalog and download or update the required regions."
        NBNavigationErrorCode.INTERRUPTED ->
            "Refresh actual state; retry only if the user still wants the operation."
        NBNavigationErrorCode.OFFLINE_REGION_ALREADY_ACTIVE,
        NBNavigationErrorCode.OFFLINE_REGION_NOT_DOWNLOADING,
        NBNavigationErrorCode.OFFLINE_REGION_NOT_PAUSED,
        NBNavigationErrorCode.OFFLINE_REGION_INVALID_STATE ->
            "Refresh observed progress before choosing the next control action."
        else -> if (error.recoverable) {
            "Retry a limited number of times after checking network and storage."
        } else {
            "Stop automatic retry and report code=${error.code}, cause=${error.causeCode}."
        }
    }
}
```

| Stable code | Retry policy | Recommended user or application action |
| --- | --- | --- |
| `INVALID_ARGUMENT` | No | Correct the request before trying again |
| `ENGINE_NOT_INITIALIZED` / `OFFLINE_SDK_NOT_REGISTERED` | After initialization | Initialize _Maps_ and _NBNavigation_, then retry once |
| `NETWORK_UNAVAILABLE` | When connectivity returns | Check _WIFI_ONLY_, _UNMETERED_, or _ANY_ and wait for a matching network |
| `TIMEOUT` | Bounded | Use exponential backoff and stop when the owning screen or request is no longer active |
| `OFFLINE_DATA_NOT_READY` | After data changes | Download every route region required by the trip |
| `OFFLINE_DATA_VERSION_MISMATCH` | After update | Synchronize catalogs and update the affected region |
| `INTERRUPTED` | User dependent | Refresh actual progress; do not restart work the user cancelled |
| `OFFLINE_REGION_NOT_FOUND` | No unchanged retry | Refresh catalogs and verify regionId |
| `OFFLINE_REGION_ALREADY_ACTIVE` | No immediate retry | Keep observing the existing task |
| `OFFLINE_REGION_NOT_DOWNLOADING` / `NOT_PAUSED` / `INVALID_STATE` | After state refresh | Choose an action that matches current progress |
| `OFFLINE_REGION_DELETE_FAILED` / `CANCEL_FAILED` | Bounded | Refresh both subsystems and retry only the incomplete operation |
| `EXECUTION_FAILED` / `INTERNAL_ERROR` / `UNKNOWN` | Bounded if recoverable | Capture _code_, _causeCode_, SDK version, and engine version for support |

A recoverable value means that restoring connectivity, freeing storage, or retrying a limited number of times may resolve the failure. It does not authorize indefinite retries. Recheck network policy, available storage, and lifecycle ownership before each retry. Use _healthCheck(callback)_ only to inspect local engine and data health and should not be used to replace the `routeNetwork` and `mapTile` completion checks.
