Understanding the Error Classification System in Open Notebook

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, this utility works alongside the exception hierarchy defined in 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. 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 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:


# 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, graphs/ask.py, and graphs/source_chat.py implement identical try-except blocks that funnel raw exceptions through the classifier.


# 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 inheriting from OpenNotebookError
  2. Add classification rules – Append tuples to _CLASSIFICATION_RULES in 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:

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:

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:


# 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 provides a single point of translation for all AI provider errors
  • Stable exception hierarchyOpenNotebookError subclasses in 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, 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. 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 inheriting from OpenNotebookError, then add a classification rule to _CLASSIFICATION_RULES in 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, graphs/ask.py, graphs/source_chat.py, and 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →