# Understanding the Error Classification System in Open Notebook

> Learn how Open Notebook centralizes provider specific failures into a clear hierarchy using an error classification system that maps raw exceptions to user friendly messages.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: internals
- Published: 2026-06-30

---

**Open Notebook centralizes provider-specific failures into a clean hierarchy of `OpenNotebookError` subclasses using a keyword-based classifier that maps raw exceptions to user-friendly messages.**

Open Notebook implements a robust error classification system that transforms cryptic AI provider errors into actionable feedback. Located in [`open_notebook/utils/error_classifier.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/error_classifier.py), this utility works alongside the exception hierarchy defined in [`open_notebook/exceptions.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/exceptions.py) to standardize how the application handles authentication failures, rate limits, and service outages. The system ensures that every LangGraph node can consistently surface readable errors to users regardless of which AI provider (OpenAI, Anthropic, Ollama) generated the underlying failure.

## Architecture of the Error Classification System

The error handling architecture consists of two primary components: a structured exception hierarchy and a classification engine that maps raw provider errors to that hierarchy.

### The Exception Hierarchy

All domain-specific errors inherit from `OpenNotebookError`, defined in [`open_notebook/exceptions.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/exceptions.py). According to the open-notebook source code, this base class provides a stable API for the rest of the application, with concrete subclasses including:

- **`AuthenticationError`** – Signals invalid API keys or unauthorized access
- **`RateLimitError`** – Indicates quota exhaustion or too many requests
- **`ExternalServiceError`** – Catches generic connectivity and service failures

### The Classification Engine

The [`open_notebook/utils/error_classifier.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/error_classifier.py) module contains the `_CLASSIFICATION_RULES` tuple list and the `classify_error()` function. This engine operates independently of any specific LLM provider, using substring matching to categorize errors without complex dependencies.

## How the Classification Logic Works

The `classify_error()` function implements a three-step normalization and matching process:

1. **Normalize the exception** – Converts the exception type name and message to lowercase, concatenating them into a combined string
2. **Keyword matching** – Iterates through `_CLASSIFICATION_RULES` to find substring matches
3. **Fallback handling** – Returns a generic `ExternalServiceError` with a truncated message if no rule matches

The classification rules structure follows this pattern:

```python

# From open_notebook/utils/error_classifier.py

_CLASSIFICATION_RULES = [
    # Authentication errors

    (["authentication", "unauthorized", "invalid api key", "invalid_api_key", "401"],
     AuthenticationError,
     "Authentication failed. Please check your API key in Settings → Credentials."),
    # Rate-limit errors

    (["rate limit", "rate_limit", "429", "too many requests", "quota exceeded"],
     RateLimitError,
     "Rate limit exceeded. Please wait a moment and try again."),
]

```

The `_truncate()` helper caps messages at 200 characters to prevent stack trace leakage. Keyword scanning uses simple substring search to keep the classifier fast and extensible without requiring regex compilation.

## Integration Points in LangGraph Nodes

Every LangGraph node that invokes LLM calls wraps its execution in a standardized error handling pattern. Files such as [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py), [`graphs/ask.py`](https://github.com/lfnovo/open-notebook/blob/main/graphs/ask.py), and [`graphs/source_chat.py`](https://github.com/lfnovo/open-notebook/blob/main/graphs/source_chat.py) implement identical try-except blocks that funnel raw exceptions through the classifier.

```python

# Simplified excerpt from open_notebook/graphs/chat.py

from open_notebook.utils.error_classifier import classify_error
from open_notebook.exceptions import OpenNotebookError

async def chat_node(state: dict) -> dict:
    try:
        response = await model.ainvoke(prompt)
        return {"output": response}
    except Exception as e:
        error_class, user_message = classify_error(e)
        raise error_class(user_message) from e

```

This pattern ensures that callers receive only `OpenNotebookError` subclasses, allowing upstream code to handle errors by type rather than parsing raw provider strings.

## Extending the Error Classification System

Adding support for new error types requires changes to only two files:

1. **Define the exception** – Add a subclass to [`open_notebook/exceptions.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/exceptions.py) inheriting from `OpenNotebookError`
2. **Add classification rules** – Append tuples to `_CLASSIFICATION_RULES` in [`open_notebook/utils/error_classifier.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/error_classifier.py) containing keywords, the target exception class, and an optional user-friendly message

Nodes that already call `classify_error()` automatically benefit from new rules without requiring modifications, as the function dynamically evaluates the rules list at classification time.

## Practical Implementation Examples

### Direct Classifier Usage

When calling LLMs outside of the standard graph nodes, wrap the invocation with the classifier:

```python
from open_notebook.utils.error_classifier import classify_error
from open_notebook.exceptions import OpenNotebookError

def safe_llm_call(model, prompt):
    try:
        return model.invoke(prompt)
    except Exception as exc:
        exc_cls, msg = classify_error(exc)
        raise exc_cls(msg) from exc

```

### Handling Errors in API Endpoints

FastAPI endpoints can catch `OpenNotebookError` subclasses to return appropriate HTTP status codes:

```python
from fastapi import APIRouter, HTTPException
from open_notebook.exceptions import OpenNotebookError

router = APIRouter()

@router.post("/chat")
async def chat_endpoint(payload: dict):
    try:
        result = await chat_service.run(payload["prompt"])
        return {"response": result}
    except OpenNotebookError as err:
        raise HTTPException(status_code=400, detail=str(err))

```

### Adding Custom Classification Rules

To handle a new "model overloaded" error from a provider:

```python

# In open_notebook/utils/error_classifier.py

_CLASSIFICATION_RULES.append(
    (["model overloaded", "overload"], ExternalServiceError,
     "The model is currently overloaded; try again later or select a smaller model.")
)

```

## Summary

- **Centralized mapping** – The `classify_error()` function in [`open_notebook/utils/error_classifier.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/error_classifier.py) provides a single point of translation for all AI provider errors
- **Stable exception hierarchy** – `OpenNotebookError` subclasses in [`open_notebook/exceptions.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/exceptions.py) offer a consistent API for error handling throughout the application
- **Simple keyword matching** – Substring search against `_CLASSIFICATION_RULES` enables fast classification without complex parsing logic
- **Automatic truncation** – Messages automatically truncate at 200 characters to prevent information leakage
- **LangGraph integration** – Nodes in [`graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/graphs/chat.py), [`graphs/ask.py`](https://github.com/lfnovo/open-notebook/blob/main/graphs/ask.py), and related files uniformly implement the pattern of catching generic exceptions and re-raising classified ones

## Frequently Asked Questions

### What file contains the error classification logic in Open Notebook?

The core classification logic resides in [`open_notebook/utils/error_classifier.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/error_classifier.py). This module defines the `classify_error()` function and the `_CLASSIFICATION_RULES` list that maps provider-specific error strings to the appropriate `OpenNotebookError` subclass.

### How does Open Notebook handle unknown provider errors?

When no keyword rule matches, the classifier logs a warning and returns a generic `ExternalServiceError` with a user message truncated to 200 characters. This prevents unhandled exceptions from exposing internal stack traces while still alerting developers through logs.

### Can I add custom error types to the classification system?

Yes. Create a new subclass in [`open_notebook/exceptions.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/exceptions.py) inheriting from `OpenNotebookError`, then add a classification rule to `_CLASSIFICATION_RULES` in [`open_notebook/utils/error_classifier.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/error_classifier.py). Any code already calling `classify_error()` will automatically recognize the new error pattern without requiring updates.

### Which LangGraph nodes implement the error classification pattern?

The pattern appears consistently across [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py), [`graphs/ask.py`](https://github.com/lfnovo/open-notebook/blob/main/graphs/ask.py), [`graphs/source_chat.py`](https://github.com/lfnovo/open-notebook/blob/main/graphs/source_chat.py), and [`graphs/transformation.py`](https://github.com/lfnovo/open-notebook/blob/main/graphs/transformation.py). Each node wraps LLM invocations in try-except blocks that call `classify_error()` before re-raising specific exception types to the graph executor.