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__ = NoneView on GitHub (pinned to bc6749cc3b)
Solutions
- Pass the expression as a string: ForwardRef('int') or ForwardRef('list[int]')
- If you already have the object, use it directly — no ForwardRef needed
- 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
- ForwardRef arguments are always strings — quote the expression
- Use Format.FORWARDREF via get_annotations instead of hand-constructing ForwardRef
- Annotate helper APIs as (ref: str) and enforce with mypy
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
- Cannot subclass ForwardRef
- name '{name:.200}' is not defined
- strptime() argument {} must be str, not {}
- Initialization arguments are not supported
- Forward reference must be an expression -- got {arg!r}
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/88f26acd91efbb56.
Report an issue: GitHub.