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

# Error Handling

> Exception hierarchy and error handling patterns for the Chatbase Android SDK.

## Exception Hierarchy

All SDK errors extend `ChatbaseException`:

```
ChatbaseException
├── ApiException        — API errors from the Chatbase server
└── NetworkException    — Connection failures, DNS errors, timeouts
```

## ApiException

`class ApiException : ChatbaseException` — **Package:** `com.chatbase.sdk.exception`

Thrown when the Chatbase API returns an error response.

```kotlin theme={null}
class ApiException(
    val httpStatus: Int,
    val errorCode: String,
    val errorMessage: String,
    val details: Map<String, String>? = null
) : ChatbaseException
```

**httpStatus** `Int` *required*

The HTTP status code of the error response (e.g. `401`, `403`, `429`).

**errorCode** `String` *required*

Machine-readable error code. Use this for programmatic handling.

**errorMessage** `String` *required*

Human-readable error description.

**details** `Map\<String, String\>?`

Optional field-level validation errors.

### Convenience Properties

```kotlin theme={null}
val isRateLimited: Boolean      // httpStatus == 429
val isNotFound: Boolean         // httpStatus == 404
val isCreditsExhausted: Boolean // httpStatus == 402
```

> [!TIP]
>
> For statuses without a helper — such as `401` (authentication) or `403` (access denied) — check `httpStatus` or `errorCode` directly.

## Error Codes

These are the error codes you may encounter through `ApiException.errorCode`:

<table>
  <thead>
    <tr>
      <th>Status</th>
      <th>Code</th>
      <th>Description</th>
    </tr>
  </thead>

  <tbody>
    <tr><td>400</td><td>`VALIDATION_INVALID_BODY`</td><td>The request body failed validation. `details` maps field names to messages. Also returned when a tool result exceeds the 20 KB limit.</td></tr>
    <tr><td>400</td><td>`CHAT_RETRY_NO_USER_MESSAGE`</td><td>The message passed to `retry()` has no preceding user message to retry from.</td></tr>
    <tr><td>401</td><td>`AUTH_INVALID_JWT`</td><td>The JWT token passed to `identify()` is invalid, expired, or could not be verified — including when identity verification is not configured for the AI agent. See [User Identity](https://chatbase.co/docs/android-sdk/user-identity.md).</td></tr>
    <tr><td>402</td><td>`CHAT_CREDITS_EXHAUSTED`</td><td>The workspace's message credit balance is zero. Upgrade the plan or wait for credits to reset. Caught by `isCreditsExhausted`.</td></tr>
    <tr><td>402</td><td>`CHAT_AGENT_CREDITS_EXHAUSTED`</td><td>The specific AI agent's credit allocation has been used up. Caught by `isCreditsExhausted`.</td></tr>
    <tr><td>403</td><td>`AUTH_OWNERSHIP_MISMATCH`</td><td>The conversation belongs to a different user or device. Also returned by `retry()` and `listMessages()` when the conversation does not exist.</td></tr>
    <tr><td>403</td><td>`CHAT_CONVERSATION_MISMATCH`</td><td>The conversation could not be resolved for this AI agent.</td></tr>
    <tr><td>403</td><td>`CHAT_MODEL_NOT_ALLOWED`</td><td>The AI agent uses a model not available on the current plan.</td></tr>
    <tr><td>403</td><td>`CHAT_CONVERSATION_NOT_ONGOING`</td><td>The conversation has ended or was taken over and cannot receive new messages. Start a new conversation.</td></tr>
    <tr><td>404</td><td>`AGENT_NOT_FOUND`</td><td>No AI agent matches the provided ID, or the **Android SDK channel is not enabled** for the AI agent (see [Quick Start](https://chatbase.co/docs/android-sdk/quickstart.md#quick-start)). Caught by `isNotFound`.</td></tr>
    <tr><td>404</td><td>`RESOURCE_NOT_FOUND`</td><td>The conversation or message does not exist. Caught by `isNotFound`.</td></tr>
    <tr><td>404</td><td>`CHAT_RETRY_MESSAGE_NOT_FOUND`</td><td>The message ID provided for `retry()` was not found. Caught by `isNotFound`.</td></tr>
    <tr><td>404</td><td>`RESOURCE_TOOL_CALL_NOT_FOUND`</td><td>The tool call was not found or has expired. Can surface through the automatic tool loop. Caught by `isNotFound`.</td></tr>
    <tr><td>404</td><td>`RESOURCE_TOOL_CALL_MISMATCH`</td><td>The tool call does not belong to this conversation. Caught by `isNotFound`.</td></tr>
    <tr><td>404</td><td>`RESOURCE_TOOL_RESULT_NOT_PENDING`</td><td>No pending tool result exists for this tool call — usually a duplicate submission. Caught by `isNotFound`.</td></tr>
    <tr><td>429</td><td>`RATE_LIMIT_TOO_MANY_REQUESTS`</td><td>Rate limit exceeded (1,000 requests per 10 seconds per device). Back off and retry. Caught by `isRateLimited`.</td></tr>
    <tr><td>500</td><td>`CHAT_STREAMING_ERROR`</td><td>The response stream failed server-side. Safe to retry.</td></tr>
    <tr><td>500</td><td>`INTERNAL_SERVER_ERROR`</td><td>An unexpected server error occurred. Retry, or contact support if it persists.</td></tr>
  </tbody>
</table>

## NetworkException

`class NetworkException : ChatbaseException` — **Package:** `com.chatbase.sdk.exception`

```kotlin theme={null}
class NetworkException(
    message: String,
    cause: Throwable? = null
) : ChatbaseException
```

Thrown for connection-level failures — DNS errors, socket timeouts, no internet connectivity, and similar issues.

## Handling Errors

**Suspend Functions**

Use a try-catch block with the SDK's exception hierarchy:

```kotlin theme={null}
try {
    val response = client.sendMessage("Hello")
} catch (e: ApiException) {
    when {
        e.httpStatus == 401 -> {
            println("Authentication failed. Check your JWT token.")
        }
        e.httpStatus == 403 -> {
            println("Access denied. Check conversation ownership or plan.")
        }
        e.isRateLimited -> {
            println("Rate limited. Back off and retry.")
        }
        e.isCreditsExhausted -> {
            println("No credits remaining. Upgrade plan.")
        }
        e.isNotFound -> {
            println("Not found. Check your agent ID.")
        }
        else -> {
            println("API error: ${e.errorCode} — ${e.errorMessage}")
        }
    }
} catch (e: NetworkException) {
    println("Network error: ${e.message}")
} catch (e: ChatbaseException) {
    println("Unknown SDK error: ${e.message}")
}
```

**Streaming Callbacks**

Handle errors via the `onError` callback:

```kotlin theme={null}
client.sendMessage("Hello") {
    onTextDelta { delta -> print(delta) }
    onError { error ->
        when (error) {
            is ApiException -> println("API error: ${error.errorCode}")
            is NetworkException -> println("Network error: ${error.message}")
            else -> println("Error: ${error.message}")
        }
    }
}
```

**Flow**

Check for `ChatStreamEvent.Error` events:

```kotlin theme={null}
client.sendMessageStream("Hello").collect { event ->
    when (event) {
        is ChatStreamEvent.TextDelta -> print(event.delta)
        is ChatStreamEvent.Error -> {
            when (val ex = event.exception) {
                is ApiException -> println("${ex.errorCode}: ${ex.errorMessage}")
                is NetworkException -> println("Network: ${ex.message}")
                else -> println("Error: ${ex.message}")
            }
        }
        else -> {}
    }
}
```

## Related

> **[Streaming](https://chatbase.co/docs/android-sdk/streaming.md)**
>
> Streaming callbacks and error events

> **[Overview](https://chatbase.co/docs/android-sdk/overview.md)**
>
> SDK setup and configuration


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