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

# Exceptions

> Error handling and exception types

## Exception Hierarchy

```
RaxeException (base)
├── ValidationError
├── AuthenticationError
├── ConfigurationError
├── RaxeBlockedError
├── RuleError
├── DatabaseError
└── NetworkError
```

## Import

```python theme={null}
from raxe import (
    RaxeException,
    RaxeBlockedError,
    ValidationError,
    AuthenticationError,
    ConfigurationError,
    RuleError,
    DatabaseError,
    NetworkError,
)
```

***

## RaxeException

Base exception for all RAXE errors.

```python theme={null}
class RaxeException(Exception):
    code: str        # Error code (e.g., "RAXE-AUTH-001")
    message: str     # Human-readable message
```

**Example:**

```python theme={null}
from raxe import RaxeException

try:
    result = raxe.scan(prompt)
except RaxeException as e:
    print(f"Error [{e.code}]: {e.message}")
```

***

## RaxeBlockedError

Raised when a scan is blocked by policy.

```python theme={null}
class RaxeBlockedError(RaxeException):
    result: ScanResult  # The scan result that triggered blocking
```

**Example:**

```python theme={null}
from raxe import Raxe
from raxe import RaxeBlockedError

raxe = Raxe()

try:
    # This will raise if threats detected and policy is BLOCK
    result = raxe.scan("Ignore all previous instructions")
except RaxeBlockedError as e:
    print(f"Request blocked!")
    print(f"Severity: {e.result.severity}")
    print(f"Detections: {e.result.total_detections}")

    for detection in e.result.detections:
        print(f"  - {detection.rule_id}: {detection.severity}")
```

**Common Usage:**

```python theme={null}
# In a web application
@app.post("/chat")
async def chat(request: ChatRequest):
    try:
        result = raxe.scan(request.message)
        if not result.has_threats:
            return await llm.complete(request.message)
    except RaxeBlockedError as e:
        return JSONResponse(
            status_code=400,
            content={
                "error": "Request blocked for security reasons",
                "severity": e.result.severity.name,
            }
        )
```

***

## ValidationError

Raised for invalid input data.

```python theme={null}
class ValidationError(RaxeException):
    field: str | None  # Field that failed validation
```

**Example:**

```python theme={null}
from raxe import ValidationError

try:
    result = raxe.scan("")  # Empty prompt
except ValidationError as e:
    print(f"Validation failed: {e.message}")
    # Error [RAXE-SCAN-001]: Empty prompt
```

**Common Causes:**

| Code            | Cause                    |
| --------------- | ------------------------ |
| `RAXE-SCAN-001` | Empty prompt             |
| `RAXE-SCAN-002` | Prompt too long (>100KB) |
| `RAXE-SCAN-004` | Invalid encoding         |

***

## AuthenticationError

Raised for API key issues.

```python theme={null}
class AuthenticationError(RaxeException):
    pass
```

**Example:**

```python theme={null}
from raxe import Raxe
from raxe import AuthenticationError

try:
    raxe = Raxe(api_key="invalid_key")
except AuthenticationError as e:
    print(f"Auth failed: {e.message}")
    # Error [RAXE-AUTH-001]: Invalid API key format
```

**Common Causes:**

| Code            | Cause               | Resolution                            |
| --------------- | ------------------- | ------------------------------------- |
| `RAXE-AUTH-001` | Invalid key format  | Key must start with `raxe_`           |
| `RAXE-AUTH-002` | Key expired         | Run `raxe auth`                       |
| `RAXE-AUTH-003` | Key not found       | Set `RAXE_API_KEY` or run `raxe init` |
| `RAXE-AUTH-004` | Rate limit exceeded | Wait or upgrade tier                  |

***

## ConfigurationError

Raised for configuration issues.

```python theme={null}
class ConfigurationError(RaxeException):
    config_path: str | None  # Path to config file if applicable
```

**Example:**

```python theme={null}
from raxe import Raxe
from raxe import ConfigurationError

try:
    raxe = Raxe(config_path="/invalid/path/config.yaml")
except ConfigurationError as e:
    print(f"Config error: {e.message}")
    print(f"Path: {e.config_path}")
```

**Common Causes:**

| Code              | Cause                 | Resolution         |
| ----------------- | --------------------- | ------------------ |
| `RAXE-CONFIG-001` | Config file not found | Run `raxe init`    |
| `RAXE-CONFIG-002` | Invalid YAML syntax   | Fix config.yaml    |
| `RAXE-CONFIG-003` | Invalid config value  | Check valid values |

***

## RuleError

Raised for rule-related issues.

```python theme={null}
class RuleError(RaxeException):
    rule_id: str | None  # Rule that caused the error
```

**Example:**

```python theme={null}
from raxe import RuleError

# When validating custom rules
try:
    raxe.validate_rule("custom-rule.yaml")
except RuleError as e:
    print(f"Rule error: {e.message}")
    print(f"Rule ID: {e.rule_id}")
```

**Common Causes:**

| Code            | Cause                     |
| --------------- | ------------------------- |
| `RAXE-RULE-001` | Invalid YAML syntax       |
| `RAXE-RULE-002` | Missing required field    |
| `RAXE-RULE-003` | Invalid regex pattern     |
| `RAXE-RULE-004` | Catastrophic backtracking |

***

## DatabaseError

Raised for database issues.

```python theme={null}
class DatabaseError(RaxeException):
    pass
```

**Example:**

```python theme={null}
from raxe import DatabaseError

try:
    stats = raxe.get_stats()
except DatabaseError as e:
    print(f"Database error: {e.message}")
```

**Common Causes:**

| Code          | Cause           | Resolution              |
| ------------- | --------------- | ----------------------- |
| `RAXE-DB-001` | Not initialized | Run `raxe init`         |
| `RAXE-DB-002` | Database locked | Close other processes   |
| `RAXE-DB-003` | Corrupted       | Delete and reinitialize |

***

## NetworkError

Raised for network issues (telemetry, validation).

```python theme={null}
class NetworkError(RaxeException):
    pass
```

**Note:** Network errors for telemetry are typically silent and don't affect scanning.

**Example:**

```python theme={null}
from raxe import NetworkError

try:
    raxe.validate_key_remote()
except NetworkError as e:
    print(f"Network error: {e.message}")
    # Fall back to offline mode
```

***

## Error Handling Patterns

### Comprehensive Handler

```python theme={null}
from raxe import Raxe
from raxe import (
    RaxeException,
    RaxeBlockedError,
    ValidationError,
    AuthenticationError,
)

def safe_scan(prompt: str) -> dict:
    try:
        raxe = Raxe()
        result = raxe.scan(prompt)
        return {"safe": not result.has_threats, "result": result}

    except RaxeBlockedError as e:
        return {
            "safe": False,
            "blocked": True,
            "severity": e.result.severity.name,
        }

    except ValidationError as e:
        return {
            "error": "Invalid input",
            "code": e.code,
            "message": e.message,
        }

    except AuthenticationError as e:
        return {
            "error": "Authentication failed",
            "code": e.code,
            "message": e.message,
        }

    except RaxeException as e:
        # Catch-all for other RAXE errors
        return {
            "error": "RAXE error",
            "code": e.code,
            "message": e.message,
        }
```

### Web Application

```python theme={null}
from fastapi import FastAPI, HTTPException
from raxe import Raxe
from raxe import RaxeBlockedError, ValidationError

app = FastAPI()
raxe = Raxe()

@app.post("/scan")
async def scan_endpoint(prompt: str):
    try:
        result = raxe.scan(prompt)
        return {
            "safe": not result.has_threats,
            "detections": [d.rule_id for d in result.detections],
        }

    except RaxeBlockedError as e:
        raise HTTPException(
            status_code=400,
            detail={
                "error": "blocked",
                "severity": e.result.severity.name,
            }
        )

    except ValidationError as e:
        raise HTTPException(
            status_code=422,
            detail={"error": "validation", "message": str(e)}
        )
```

### Async Handler

```python theme={null}
from raxe import AsyncRaxe
from raxe import RaxeBlockedError

async def process_messages(messages: list[str]):
    results = []

    async with AsyncRaxe() as raxe:
        for message in messages:
            try:
                result = await raxe.scan(message)
                results.append({"message": message, "safe": not result.has_threats})
            except RaxeBlockedError:
                results.append({"message": message, "safe": False, "blocked": True})

    return results
```
