python/cpython · error · NameError

name '{name:.200}' is not defined

Error message

name '{name:.200}' is not defined

What it means

When ForwardRef.evaluate() resolves a simple identifier, it looks in locals, then globals, then builtins; if the name is found nowhere and the target format is not a forward-ref-preserving format, it raises NameError with the standard message and a `name=` keyword carrying the unresolved identifier. This mirrors normal Python name resolution for annotation strings.

Source

Thrown at Lib/annotationlib.py:203

                    pass
                else:
                    locals.setdefault(cell_name, cell_value)

        if self.__extra_names__:
            locals.update(self.__extra_names__)

        arg = self.__forward_arg__
        if arg.isidentifier() and not keyword.iskeyword(arg):
            if arg in locals:
                return locals[arg]
            elif arg in globals:
                return globals[arg]
            elif hasattr(builtins, arg):
                return getattr(builtins, arg)
            elif is_forwardref_format:
                return self
            else:
                raise NameError(_NAME_ERROR_MSG.format(name=arg), name=arg)
        else:
            code = self.__forward_code__
            try:
                return eval(code, globals=globals, locals=locals)
            except Exception:
                if not is_forwardref_format:
                    raise

            # All variables, in scoping order, should be checked before
            # triggering __missing__ to create a _Stringifier.
            new_locals = _StringifierDict(
                {**builtins.__dict__, **globals, **locals},
                globals=globals,
                owner=owner,
                is_class=self.__forward_is_class__,
                format=format,
            )
            try:

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Import or define the referenced name so it is resolvable at evaluation time
  2. Pass the defining module's namespace: ForwardRef('X').evaluate(globals=vars(module))
  3. Guard imports used only for annotations under TYPE_CHECKING and evaluate lazily only when needed
  4. Catch NameError and fall back to Format.FORWARDREF/STRING format to defer resolution

Example fix

# before
from __future__ import annotations

def parse() -> Result: ...   # NameError: name 'Result' is not defined (on get_type_hints)

# after
from __future__ import annotations
from mymod import Result

def parse() -> Result: ...
Defensive patterns

Strategy: try-catch

Validate before calling

def evaluate_ref(fr, module_globals):
    try:
        return fr.evaluate(globals=module_globals)
    except NameError:
        return None  # defer: unresolved symbol

Type guard

def name_resolvable(name: str, globals_ns: dict, locals_ns: dict = None) -> bool:
    import builtins
    scopes = [locals_ns or {}, globals_ns, vars(builtins)]
    return any(name in s for s in scopes)

Try / catch

from annotationlib import ForwardRef, Format

try:
    obj = fr.evaluate(globals=ns)
except NameError as e:
    if getattr(e, 'name', None) == target_name:
        obj = fr.evaluate(globals=ns, format=Format.FORWARDREF)  # keep as ForwardRef
    else:
        raise

Prevention

When it happens

Trigger: ForwardRef('Missing').evaluate(); typing.get_type_hymes on annotations referencing names deleted/renamed/moved; class-level annotations like 'def f(self) -> Result:' where Result was never imported or was defined after use under `from __future__ import annotations`.

Common situations: Refactors that move classes without updating string annotations; TYPE_CHECKING-only imports used at runtime; deserialized/pickled annotation strings evaluated in a fresh namespace lacking the original module globals.

Related errors


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