python/cpython · error · ValueError

eval_str=True is only supported with format=Format.VALUE

Error message

eval_str=True is only supported with format=Format.VALUE

What it means

annotationlib.get_annotations() rejects eval_str=True unless format is Format.VALUE. eval_str exists to evaluate string annotations into objects, which is only meaningful in VALUE format; combining it with STRING or FORWARDREF is contradictory, so it raises ValueError immediately.

Source

Thrown at Lib/annotationlib.py:959

      * If eval_str is true, eval() is called on values of type str.
      * If eval_str is false (the default), values of type str are unchanged.

    globals and locals are passed in to eval(); see the documentation
    for eval() for more information.  If either globals or locals is
    None, this function may replace that value with a context-specific
    default, contingent on type(obj):

      * If obj is a module, globals defaults to obj.__dict__.
      * If obj is a class, globals defaults to
        sys.modules[obj.__module__].__dict__ and locals
        defaults to the obj class namespace.
      * If obj is a callable, globals defaults to obj.__globals__,
        although if obj is a wrapped function (using
        functools.update_wrapper()) it is first unwrapped.
    """
    if eval_str and format != Format.VALUE:
        raise ValueError("eval_str=True is only supported with format=Format.VALUE")

    match format:
        case Format.VALUE:
            # For VALUE, we first look at __annotations__
            ann = _get_dunder_annotations(obj)

            # If it's not there, try __annotate__ instead
            if ann is None:
                ann = _get_and_call_annotate(obj, format)
        case Format.FORWARDREF:
            # For FORWARDREF, we use __annotations__ if it exists
            try:
                ann = _get_dunder_annotations(obj)
            except Exception:
                pass
            else:
                if ann is not None:
                    return dict(ann)

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Drop the format argument (VALUE is the default) when you need eval_str=True.
  2. Or set eval_str=False and post-process ForwardRef objects yourself when working in FORWARDREF format.
  3. Validate the parameter pair at your own API boundary: reject eval_str and format != VALUE early with your own message.

Example fix

# before
ann = get_annotations(func, eval_str=True, format=Format.FORWARDREF)  # ValueError

# after
ann = get_annotations(func, eval_str=True)  # format defaults to Format.VALUE
Defensive patterns

Strategy: validation

Validate before calling

from annotationlib import Format

def validate_get_annotations_kwargs(eval_str: bool, format=Format.VALUE):
    if eval_str and format != Format.VALUE:
        raise ValueError('eval_str=True requires the default VALUE format')

Try / catch

try:
    ann = get_annotations(obj, eval_str=eval_str, format=fmt)
except ValueError as e:
    if 'eval_str=True is only supported' in str(e):
        ann = get_annotations(obj, eval_str=eval_str)  # retry with default VALUE format
    else:
        raise

Prevention

When it happens

Trigger: get_annotations(func, eval_str=True, format=Format.STRING); get_annotations(cls, eval_str=True, format=Format.FORWARDREF); wrapping inspect.get_annotations-like logic while forwarding both parameters from user input.

Common situations: CLI/tooling exposing both eval_str and format flags and passing them through; porting code from inspect.get_annotations (which is implicitly VALUE-only) while adding a format argument; copy-pasted snippets mixing parameters.

Related errors


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