2025, Oct 03 21:00

Type-hinting SQLAlchemy Sessions in FastAPI: Resolve Pylance 'Variable not allowed in type expression' with Generator[Session]

Learn how to type-hint a SQLAlchemy session dependency in FastAPI and fix Pylance 'Variable not allowed in type expression' by annotating Generator[Session].

Type-hinting a SQLAlchemy session dependency in a FastAPI-style setup often runs into a Pylance warning: “Variable not allowed in type expression.” It appears when you annotate the return type with a value produced by sessionmaker rather than with the actual type of the yielded object. The fix is straightforward once you look at what the function really returns.

Problem

Consider a minimal dependency that opens a database session and yields it:

from sqlalchemy.orm import sessionmaker
SessionBuilder = sessionmaker(db_engine, **sa_session_cfg)
def open_session() -> SessionBuilder:
    with SessionBuilder() as conn:
        yield conn

Pylance flags the annotation “-> SessionBuilder” with “Variable not allowed in type expression.”

What’s going on

You can make the type checker reveal what instance comes out of the factory. Using reveal_type shows that calling the sessionmaker instance produces a Session:

from typing import reveal_type
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
tmp_engine = create_engine("sqlite:///:memory:")
BuildSession = sessionmaker(tmp_engine)
reveal_type(BuildSession())

$ pyright stackoverflow.py
/path/to/example/stackoverflow.py
/path/to/example/stackoverflow.py:8:13 - information: Type of "BuildSession()" is "Session"
0 errors, 0 warnings, 1 information

If the function were regular (no yield), the return type would simply be Session. But because it uses yield, it returns a generator whose yielded value is a Session. That’s why the annotation must target the yielded type, not the variable holding the factory.

Solution

Annotate the function as returning a generator that yields Session. This removes the warning and expresses intent accurately:

from typing import Generator
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
core_engine = create_engine("sqlite:///:memory:")
SessionFactory = sessionmaker(core_engine)
def provide_session() -> Generator[Session]:
    with SessionFactory() as handle:
        yield handle

Here the function yields a Session, so Generator[Session] is the correct annotation. If it were not a generator and simply returned the object, the type would be Session.

Why this matters

Accurate annotations help the type checker understand control flow and catch real issues instead of surface-level warnings. It also clarifies what the dependency provides to its consumers: a yielded Session rather than a factory value.

Takeaways

Use a type checker to confirm what a factory returns, then annotate against that type. For generator-based dependencies that yield a resource, annotate the return type as a Generator of that resource. In this case, the correct form is Generator[Session], not the variable that holds the sessionmaker.

The article is based on a question from StackOverflow by postcoital-solitaire and an answer by daveruinseverything.