pallets/flask · error · TypeError

{exc_class!r} is an instance, not a class. Handlers can only

Error message

{exc_class!r} is an instance, not a class. Handlers can only be registered for Exception classes or HTTP error codes.

What it means

Error handlers are registered per exception class, then matched at runtime against raised instances via the class's MRO. Passing an exception instance (e.g. ValueError('bad')) instead of the class would break that lookup, so _get_exc_class_and_code raises TypeError immediately at registration time.

Source

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

        :param exc_class_or_code: Any exception class, or an HTTP status
            code as an integer.
        """
        exc_class: type[Exception]

        if isinstance(exc_class_or_code, int):
            try:
                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

View on GitHub ↗ (pinned to 6a2f545bfd)

Solutions

  1. Drop the parentheses / pass the class itself: @app.errorhandler(ValueError).
  2. If you have an instance in hand, register its type: app.register_error_handler(type(e), fn).

Example fix

# before
@app.errorhandler(ValueError())
def handle(e): ...
# after
@app.errorhandler(ValueError)
def handle(e): ...
Defensive patterns

Strategy: type-guard

Type guard

import inspect
def is_valid_handler_key(key) -> bool:
    return isinstance(key, int) or (inspect.isclass(key) and issubclass(key, Exception))

Prevention

When it happens

Trigger: app.register_error_handler(ValueError('oops'), fn) or @app.errorhandler(SomeError()) — i.e. the argument has parentheses, instantiating the exception rather than referencing the class.

Common situations: Accidentally calling the exception class in the decorator; passing a caught exception object (except Exception as e: app.register_error_handler(e, ...)); confusion with APIs that accept instances.

Related errors


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