pallets/flask · error · ValueError

'{exc_class.__name__}' is not a subclass of Exception. Handl

Error message

'{exc_class.__name__}' is not a subclass of Exception. Handlers can only be registered for Exception classes or HTTP error codes.

What it means

Flask validates that a registered handler key is actually an Exception subclass, because runtime matching walks the raised exception's class hierarchy. A non-exception class (or any non-int, non-exception object) can never match a raised exception, so registration fails fast with ValueError.

Source

Thrown at src/flask/sansio/scaffold.py:689

                exc_class = default_exceptions[exc_class_or_code]
            except KeyError:
                raise ValueError(
                    f"'{exc_class_or_code}' is not a recognized HTTP"
                    " error code. Use a subclass of HTTPException with"
                    " that code instead."
                ) from None
        else:
            exc_class = exc_class_or_code

        if isinstance(exc_class, Exception):
            raise TypeError(
                f"{exc_class!r} is an instance, not a class. Handlers"
                " can only be registered for Exception classes or HTTP"
                " error codes."
            )

        if not issubclass(exc_class, Exception):
            raise ValueError(
                f"'{exc_class.__name__}' is not a subclass of Exception."
                " Handlers can only be registered for Exception classes"
                " or HTTP error codes."
            )

        if issubclass(exc_class, HTTPException):
            return exc_class, exc_class.code
        else:
            return exc_class, None


def _endpoint_from_view_func(view_func: ft.RouteCallable) -> str:
    """Internal helper that returns the default endpoint for a given
    function.  This always is the function name.
    """
    assert view_func is not None, "expected view func if endpoint is not provided."
    return view_func.__name__

View on GitHub ↗ (pinned to 6a2f545bfd)

Solutions

  1. Make the custom error class inherit from Exception (or a subclass like RuntimeError/HTTPException).
  2. If you meant an HTTP status, pass the integer code (e.g. 404) instead of a class.
  3. Check imports — ensure you're referencing the exception class, not a similarly named model or constant.

Example fix

# before
class PaymentError: ...
@app.errorhandler(PaymentError)
def handle(e): ...
# after
class PaymentError(Exception): ...
@app.errorhandler(PaymentError)
def handle(e): ...
Defensive patterns

Strategy: type-guard

Validate before calling

import inspect
assert inspect.isclass(exc) and issubclass(exc, Exception), f"{exc!r} must subclass Exception"

Type guard

import inspect
def is_exception_class(obj) -> bool:
    return inspect.isclass(obj) and issubclass(obj, Exception)

Prevention

When it happens

Trigger: @app.errorhandler(SomeClass) or register_error_handler where SomeClass does not inherit from Exception — e.g. a plain class, a BaseException-only subclass (KeyboardInterrupt-style custom), a string, or an enum member.

Common situations: Custom 'error' classes that forgot to inherit Exception; passing a status-code enum instead of an int; registering a Werkzeug Response class or a sentinel by mistake.

Related errors


AI-assisted analysis of pallets/flask@6a2f545bfd (2026-07-31). Data as JSON: /data/errors/c907ba7c31bf9136.json. Report an issue: GitHub ↗.