python/cpython · error · TypeError

Forward reference must be a string -- got {arg!r}

Error message

Forward reference must be a string -- got {arg!r}

What it means

annotationlib.ForwardRef (the modern typing.ForwardRef) requires its positional argument to be a string containing the forward reference expression. __init__ raises TypeError immediately for any non-str argument (int, type object, None, ...).

Source

Thrown at Lib/annotationlib.py:79

    * owner: The owning object (module, class, or function).
    * is_argument: Does nothing, retained for compatibility.
    * is_class: True if the forward reference was created in class scope.

    """

    __slots__ = _SLOTS

    def __init__(
        self,
        arg,
        *,
        module=None,
        owner=None,
        is_argument=True,
        is_class=False,
    ):
        if not isinstance(arg, str):
            raise TypeError(f"Forward reference must be a string -- got {arg!r}")

        self.__arg__ = arg
        self.__forward_is_argument__ = is_argument
        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

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Pass the expression as a string: ForwardRef('int') or ForwardRef('list[int]')
  2. If you already have the object, use it directly — no ForwardRef needed
  3. To stringify an object, use annotationlib.get_annotations(..., format=Format.FORWARDREF) rather than hand-building

Example fix

# before
>>> from annotationlib import ForwardRef
>>> ForwardRef(list[int])
TypeError: Forward reference must be a string -- got list[int]

# after
>>> ForwardRef('list[int]')
ForwardRef('list[int]')
Defensive patterns

Strategy: type-guard

Validate before calling

from annotationlib import ForwardRef

def make_forwardref(arg):
    return ForwardRef(arg if isinstance(arg, str) else str(arg))

Type guard

def is_forwardref_arg(arg) -> bool:
    return isinstance(arg, str)

Try / catch

try:
    fr = ForwardRef(value)
except TypeError:
    fr = ForwardRef(str(value))  # or use value directly if already a type

Prevention

When it happens

Trigger: ForwardRef(int) or ForwardRef(None) instead of ForwardRef('int'); passing an already-evaluated type where a string is expected, e.g. building annotations programmatically: {'x': ForwardRef(list[int])}.

Common situations: Metaprogramming that constructs annotation objects; migrating from typing.ForwardRef misuse; wrapping values obtained from get_type_hints (already objects) back into ForwardRef.

Related errors


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