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

# Error Handling

> Recommended patterns for handling errors and retries

## Exception hierarchy

All Vrin SDK exceptions inherit from `VRINError`:

```
VRINError
  +-- AuthenticationError    # Invalid/expired API key (401)
  +-- RateLimitError         # Rate limit exceeded (429)
  +-- ValidationError        # Invalid input
  +-- ServiceUnavailableError # Server error (5xx)
  +-- JobFailedError         # Async job failed
  +-- TimeoutError           # Operation timed out
  +-- InsufficientCoverageError  # No relevant knowledge
  +-- StreamingError         # SSE stream error
```

## Basic error handling

```python theme={null}
from vrin import VRINClient, VRINError

client = VRINClient(api_key="vrin_live_abc123def456ghi789jkl012mno345pq")

try:
    result = client.query("What is ACME's revenue?")
except VRINError as e:
    print(f"Vrin error: {e}")
```

## Granular error handling

```python theme={null}
from vrin import (
    VRINClient,
    AuthenticationError,
    RateLimitError,
    ServiceUnavailableError,
    TimeoutError,
    VRINError,
)

try:
    result = client.query("What is ACME's revenue?")
except AuthenticationError:
    # API key is invalid or expired -- cannot retry
    print("Check your API key")
except RateLimitError:
    # Back off and retry
    print("Rate limited -- wait before retrying")
except ServiceUnavailableError:
    # Server error -- the client already retried (max_retries times)
    print("Service temporarily unavailable")
except TimeoutError:
    # Request took too long
    print("Request timed out")
except VRINError as e:
    # Catch-all for any other Vrin error
    print(f"Unexpected error: {e}")
```

## Retry patterns

The client has built-in retry for server errors (5xx) and connection failures. For rate limits, implement your own backoff:

```python theme={null}
import time
from vrin import RateLimitError

def query_with_backoff(client, query, max_attempts=3):
    for attempt in range(max_attempts):
        try:
            return client.query(query)
        except RateLimitError:
            if attempt < max_attempts - 1:
                wait = 2 ** attempt
                time.sleep(wait)
                continue
            raise
```

## Handling async job failures

```python theme={null}
from vrin import JobFailedError, TimeoutError

try:
    result = client.insert("content...", title="My Doc", max_wait=60.0)
except JobFailedError as e:
    print(f"Processing failed: {e}")
    # Content may be partially indexed -- check job status for details
except TimeoutError:
    print("Job still running -- check status manually")
    # The job may still complete successfully
```

## Streaming error handling

```python theme={null}
from vrin import StreamingError

try:
    for token in client.query("test", stream=True):
        print(token, end="")
except StreamingError as e:
    print(f"\nStream error: {e}")
```

You can also check for errors after iteration:

```python theme={null}
resp = client.query("test", stream=True)
for token in resp:
    print(token, end="")

if resp.error:
    print(f"\nError during stream: {resp.error}")
if resp.insufficient_coverage:
    print("\nNo relevant knowledge found")
```

## Insufficient coverage

When the knowledge base has no relevant facts, Vrin returns early without calling the LLM:

```python theme={null}
result = client.query("What is the weather on Mars?")
if result.get("insufficient_coverage"):
    print("I don't have knowledge about this topic")
else:
    print(result["summary"])
```

This is not an error -- it means the query is outside the scope of your knowledge base.
