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
- Drop the format argument (VALUE is the default) when you need eval_str=True.
- Or set eval_str=False and post-process ForwardRef objects yourself when working in FORWARDREF format.
- 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
- Never forward both eval_str and a non-VALUE format from tool flags
- Default format to Format.VALUE in wrappers
- Document that eval_str implies VALUE format
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
- Forward reference must be an expression -- got {arg!r}
- Cannot stringify annotation containing string formatting
- The VALUE_WITH_FAKE_GLOBALS format is for internal use only
- annotate function does not support VALUE format
- Invalid format: {format!r}
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/ec67b1bc201f0655.
Report an issue: GitHub.