python/cpython · error · ValueError

Unsupported format {format!r}

Error message

Unsupported format {format!r}

What it means

The wildcard case in get_annotations()'s format match raises ValueError('Unsupported format {format!r}') for anything that is not a known Format member. Unlike the sibling 'Invalid format' check in call_annotate_function, this fires on the public API when the format argument is an invalid integer, an unrelated enum, or an unhashable/odd value that simply matches no case.

Source

Thrown at Lib/annotationlib.py:998

            ann = _get_and_call_annotate(obj, format)
            if ann is None:
                # If that didn't work either, we have a very weird object: evaluating
                # __annotations__ threw NameError and there is no __annotate__. In that case,
                # we fall back to trying __annotations__ again.
                ann = _get_dunder_annotations(obj)
        case Format.STRING:
            # For STRING, we try to call __annotate__
            ann = _get_and_call_annotate(obj, format)
            if ann is not None:
                return dict(ann)
            # But if we didn't get it, we use __annotations__ instead.
            ann = _get_dunder_annotations(obj)
            if ann is not None:
                return annotations_to_string(ann)
        case Format.VALUE_WITH_FAKE_GLOBALS:
            raise ValueError("The VALUE_WITH_FAKE_GLOBALS format is for internal use only")
        case _:
            raise ValueError(f"Unsupported format {format!r}")

    if ann is None:
        if isinstance(obj, type) or callable(obj):
            return {}
        raise TypeError(f"{obj!r} does not have annotations")

    if not ann:
        return {}

    if not eval_str:
        return dict(ann)

    if globals is None or locals is None:
        if isinstance(obj, type):
            # class
            obj_globals = None
            module_name = getattr(obj, "__module__", None)
            if module_name:

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Pass a real Format member (Format.VALUE / STRING / FORWARDREF).
  2. Coerce untrusted input via `Format.try_value(value)` or `Format(value)` inside try/except before calling.
  3. Default the format parameter to Format.VALUE in your own wrappers instead of None passthrough.

Example fix

# before
fmt = request.args.get('format')  # e.g. 'VALUE' string
ann = get_annotations(obj, format=fmt)  # ValueError: Unsupported format 'VALUE'

# after
fmt = Format[request.args.get('format', 'VALUE').upper()]
ann = get_annotations(obj, format=fmt)
Defensive patterns

Strategy: validation

Validate before calling

from annotationlib import Format

def parse_format(raw):
    if isinstance(raw, Format):
        return raw
    try:
        return Format(raw)
    except ValueError:
        raise ValueError(f'unsupported format {raw!r}; expected one of VALUE, STRING, FORWARDREF')

Type guard

from annotationlib import Format

def is_supported_format(fmt) -> bool:
    return isinstance(fmt, Format) and fmt in (Format.VALUE, Format.STRING, Format.FORWARDREF)

Try / catch

try:
    ann = get_annotations(obj, format=fmt)
except ValueError as e:
    if 'Unsupported format' in str(e):
        fmt = Format.VALUE
        ann = get_annotations(obj, format=fmt)
    else:
        raise

Prevention

When it happens

Trigger: get_annotations(obj, format=99); get_annotations(obj, format='string'); passing a custom IntEnum that coincidentally overlaps no case; forwarding a user-supplied format parameter unchecked.

Common situations: Configuration-driven format selection parsed from config files as strings or ints; desynchronized enum values between interpreter and library code; typos in keyword arguments.

Related errors


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