sqlalchemy/sqlalchemy · error · ArgumentError

No type information could be extracted from annotation {anno

Error message

No type information could be extracted from annotation {annotation} for attribute '{base.__name__}.{name}'

What it means

When a TypedColumns attribute has only an annotation (no Column instance) SQLAlchemy extracts a Python type from the annotation to infer the SQL type. If _collect_annotation cannot extract any usable type (returns _NoArg.NO_ARG) - e.g. the annotation is bare Named/Column with no parameter, or resolves to a non-generic base - an ArgumentError is raised naming the offending annotation and attribute.

Source

Thrown at lib/sqlalchemy/sql/_annotated_cols.py:279

        cls_annotations = util.get_annotations(base)
        cls_vars = vars(base)
        items = [
            (n, cls_vars.get(n), cls_annotations.get(n))
            for n in util.merge_lists_w_ordering(
                list(cls_vars), list(cls_annotations)
            )
            if not dunders_re.match(n)
        ]
        # --
        for name, obj, annotation in items:
            if obj is None:
                assert annotation is not None
                # no attribute, just annotation
                extracted_type = _collect_annotation(
                    table_columns_cls, name, base.__module__, annotation
                )
                if extracted_type is _NoArg.NO_ARG:
                    raise ArgumentError(
                        "No type information could be extracted from "
                        f"annotation {annotation} for attribute "
                        f"'{base.__name__}.{name}'"
                    )
                sqltype = _get_sqltype(extracted_type)
                if sqltype is None:
                    raise ArgumentError(
                        f"Could not find a SQL type for type {extracted_type} "
                        f"obtained from annotation {annotation} in "
                        f"attribute '{base.__name__}.{name}'"
                    )
                columns[name] = Column(
                    name,
                    sqltype,
                    nullable=sa_typing.includes_none(extracted_type),
                )
            elif isinstance(obj, Column):
                # has attribute attribute

View on GitHub (pinned to d9b44cb731)

Solutions

  1. Provide a concrete type argument to Named or Column: `name: Named[str]` or `name: Column[String]`
  2. Ensure forward references (string annotations) resolve to a generic Named[...] / Column[...] at evaluation time
  3. If you need full control over the type, assign a Column instance instead of relying on annotation inference: `name = Column(String)`

Example fix

# before
class Cols(TypedColumns):
    name: Named   # no type info extractable

# after
class Cols(TypedColumns):
    name: Named[str]
Defensive patterns

Strategy: validation

Validate before calling

import typing
# Surface annotation problems BEFORE building the table
hints = typing.get_type_hints(MyCols)
for name, ann in hints.items():
    origin = typing.get_origin(ann)
    args = typing.get_args(ann)
    if origin is None or not args:
        raise ValueError(
            f"{MyCols.__name__}.{name}: annotation {ann!r} carries no inner type; "
            "use Column[<pytype>] or Named[<pytype>]."
        )

Prevention

When it happens

Trigger: Declaring an attribute like `name: Named` (missing type arg) or `name: SomeNonGenericType` in a TypedColumns subclass. Also triggered by annotations that de-stringify to a bare Named/Column class rather than a generic like Named[str].

Common situations: Forgetting the type parameter on Named, using forward references that resolve to the wrong shape, or copy-pasting annotation styles that work in ORM mapped classes but are too vague for TypedColumns inference.

Related errors


AI-assisted analysis of sqlalchemy/sqlalchemy@d9b44cb731 (2026-08-01). Data as JSON: /data/errors/8e836a280d9a842f.json. Report an issue: GitHub.