python/cpython · error · TypeError

Cannot subclass ForwardRef

Error message

Cannot subclass ForwardRef

What it means

ForwardRef sets __init_subclass__ to unconditionally raise TypeError('Cannot subclass ForwardRef'). The class is treated as a final implementation detail of the annotation machinery, so subclassing to tweak evaluation is disallowed.

Source

Thrown at Lib/annotationlib.py:101

        self.__forward_is_class__ = is_class
        self.__forward_module__ = module
        self.__owner__ = owner
        # These are always set to None here but may be non-None if a ForwardRef
        # is created through __class__ assignment on a _Stringifier object.
        self.__globals__ = None
        # This may be either a cell object (for a ForwardRef referring to a single name)
        # or a dict mapping cell names to cell objects (for a ForwardRef containing references
        # to multiple names).
        self.__cell__ = None
        self.__extra_names__ = None
        # These are initially None but serve as a cache and may be set to a non-None
        # value later.
        self.__code__ = None
        self.__ast_node__ = None
        self.__resolved_str_cache__ = None

    def __init_subclass__(cls, /, *args, **kwds):
        raise TypeError("Cannot subclass ForwardRef")

    def evaluate(
        self,
        *,
        globals=None,
        locals=None,
        type_params=None,
        owner=None,
        format=Format.VALUE,
    ):
        """Evaluate the forward reference and return the value.

        If the forward reference cannot be evaluated, raise an exception.
        """
        match format:
            case Format.STRING:
                return self.__resolved_str__
            case Format.VALUE:

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Wrap instead of subclass: hold a ForwardRef instance in your own class and delegate .evaluate()
  2. Customize evaluation by passing globals/locals/owner/type_params to ForwardRef.evaluate()
  3. For custom annotation semantics, implement __annotations__ via AnnotationArray/_AnnotatedAlias-style composition instead of inheritance

Example fix

# before
class MyRef(ForwardRef):  # TypeError: Cannot subclass ForwardRef
    pass

# after
class MyRef:
    def __init__(self, ref: str):
        self._ref = ForwardRef(ref)
    def evaluate(self, **kw):
        return self._ref.evaluate(**kw)
Defensive patterns

Strategy: type-guard

Validate before calling

from annotationlib import ForwardRef

def is_final(cls) -> bool:
    return getattr(cls, '__init_subclass__', None) is not None and 'Cannot subclass' in getattr(cls.__init_subclass__, '__doc__' if False else '', '') or cls is ForwardRef

Type guard

from annotationlib import ForwardRef

def can_subclass(base) -> bool:
    try:
        type('Probe', (base,), {})
        return True
    except TypeError:
        return False

Try / catch

try:
    class MyRef(ForwardRef):
        pass
except TypeError:
    class MyRef:  # delegation fallback
        def __init__(self, ref):
            self._ref = ForwardRef(ref)

Prevention

When it happens

Trigger: class MyRef(ForwardRef): ... — at class-creation time (instance creation never happens), __init_subclass__ fires and raises.

Common situations: Libraries trying to subclass ForwardRef to add lazy caching or custom name resolution (a pattern that worked with older typing internals); porting typing-extension code to Python 3.14's annotationlib.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/1940c7be6b3c3c4d. Report an issue: GitHub.