How the Open Notebook Error Classification System Maps LLM Exceptions to HTTP Responses

The Open Notebook error classification system converts raw LLM provider exceptions into structured OpenNotebookError subclasses through keyword-based rules in open_notebook/utils/error_classifier.py, then translates those errors into standard HTTP responses via a centralized FastAPI exception handler in api/main.py.

The lfnovo/open-notebook repository centralizes the translation of low-level LLM exceptions into user-friendly HTTP responses. Its error classification system intercepts failures from providers like Esperanto and LangChain, then surfaces them to API consumers as clear messages with precise status codes. This pipeline ensures that authentication errors, rate limits, and network timeouts never leak internal stack traces.

Keyword-Based Rules in open_notebook/utils/error_classifier.py

The core of the error classification system is _CLASSIFICATION_RULES, an ordered list defined in open_notebook/utils/error_classifier.py. Each rule pairs a set of search strings with a concrete subclass of OpenNotebookError and an optional human-readable message.

  • Authentication failures: Keywords like "authentication" and "unauthorized" map to AuthenticationError with a message indicating that authentication failed (lines 20–27).
  • Rate limiting: Strings like "rate limit" and "429" trigger RateLimitError with a "Rate limit exceeded" explanation (lines 28–33).
  • Network issues: Terms such as "connecterror" and "timeout" resolve to NetworkError, signaling that the application could not connect to the AI provider (lines 45–50).

Additional rules cover configuration errors, context-length violations, payload-size issues, and generic provider failures.

How classify_error Inspects and Labels Exceptions

When a raw exception bubbles up to the application boundary, routers call classify_error(exception) at lines 72–96 of error_classifier.py. The function lowercases the exception's type name and message, concatenates them into a combined search string, and scans _CLASSIFICATION_RULES in order. The first matching rule determines the classified error type.

If a rule matches, classify_error returns the corresponding OpenNotebookError subclass and a prepared user-friendly message—or a truncated fallback of the original text. When no rule matches, the function logs the anomaly and defaults to a generic ExternalServiceError.

Mapping Classified Errors to HTTP Responses in api/main.py

The global exception handler registered in api/main.py translates each OpenNotebookError subclass into a specific HTTP status code. The handler returns a JSONResponse containing the error's detail string.

@app.exception_handler(OpenNotebookError)
async def open_notebook_error_handler(request: Request, exc: OpenNotebookError):
    if isinstance(exc, AuthenticationError):
        status = 401
    elif isinstance(exc, RateLimitError):
        status = 429
    elif isinstance(exc, ConfigurationError):
        status = 400
    elif isinstance(exc, NetworkError):
        status = 502
    elif isinstance(exc, ExternalServiceError):
        status = 502
    else:
        status = 500
    return JSONResponse(status_code=status, content={"detail": str(exc)})

This mapping produces the following outcomes:

  • AuthenticationError401 Unauthorized
  • RateLimitError429 Too Many Requests
  • ConfigurationError400 Bad Request
  • NetworkError502 Bad Gateway
  • ExternalServiceError502 Bad Gateway
  • All other errors → 500 Internal Server Error

Router-Level Integration of the Error Classification System

API routes catch broad exceptions and delegate translation to the classification system. In api/routers/source_chat.py (lines 74–80), a typical endpoint wraps its LLM call like this:

except Exception as e:
    # Translate the raw exception into a classified OpenNotebookError

    error_class, user_message = classify_error(e)
    # FastAPI will route this through the global error handler,

    # which maps the error_class to an appropriate HTTP status.

    raise HTTPException(status_code=500, detail=user_message)

Although the router raises an HTTPException with status_code=500, the global handler in api/main.py intercepts the underlying classified error and overrides the final response with the correct status code and detail.

For example, if a low-level LLM library throws a TimeoutError, the "timeout" keyword matches the network rule, classify_error returns NetworkError, and the client receives an HTTP 502 response:

{
  "detail": "Could not connect to the AI provider. Please check your network connection and provider URL."
}

Summary

  • Centralized rules: open_notebook/utils/error_classifier.py defines _CLASSIFICATION_RULES, pairing LLM exception keywords with structured OpenNotebookError subclasses.
  • Classifier function: classify_error() inspects exception text and returns the first matching error type plus a user-friendly message.
  • HTTP translation: api/main.py hosts a global FastAPI exception handler that maps each error subclass to a standard HTTP status code.
  • Router pattern: API routes in files like api/routers/source_chat.py call classify_error() inside broad except Exception blocks to ensure every provider failure surfaces as a clean HTTP response.

Frequently Asked Questions

What happens if an LLM exception does not match any classification rule?

classify_error() logs the unrecognized exception and returns the generic ExternalServiceError subclass. The global FastAPI handler in api/main.py then translates this into an HTTP 502 Bad Gateway response.

Which HTTP status code does the system return for rate limit errors?

When the exception text contains keywords like "rate limit" or "429", the error classification system produces a RateLimitError. The global handler maps this to HTTP 429 Too Many Requests.

Can the error classification system handle authentication failures from any LLM provider?

Yes. Because classify_error() matches on keyword substrings rather than exact exception types, any provider raising an exception that includes terms like "authentication" or "unauthorized" is classified as AuthenticationError and returned as HTTP 401 Unauthorized.

Where is the error hierarchy defined in the Open Notebook codebase?

The OpenNotebookError base class and its subclasses—such as AuthenticationError, RateLimitError, and NetworkError—are defined in open_notebook/exceptions.py. The classification rules in error_classifier.py and the HTTP handler in api/main.py both depend on this hierarchy.

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 →