TypedDict does not satisfy TypedDictLikeV1 protocol under ty type checker #1151

Open
opened 2026-02-20 17:43:15 -05:00 by yindo · 0 comments
Owner

Originally created by @5hal1n on GitHub (Feb 16, 2026).

Description

When using ty (Astral's type checker for Python), StateGraph(MyState) raises invalid-argument-type for any TypedDict-based state class. This is because ty cannot statically verify that Python's TypedDict satisfies the TypedDictLikeV1 protocol.

Reproduction

from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, add_messages
from langchain_core.messages import BaseMessage

class MyState(TypedDict, total=False):
    messages: Annotated[list[BaseMessage], add_messages]
    user_id: str

builder = StateGraph(MyState)  # ty error: invalid-argument-type

Running ty check produces:

error[invalid-argument-type]: Argument to bound method `__init__` is incorrect
  --> graph.py:9:22
   |
 9 | builder = StateGraph(MyState)
   |                      ^^^^^^^ Argument type `MyState` does not satisfy upper bound
   |                               `TypedDictLikeV1 | DataclassLike` of type variable `StateT`

Root Cause

In langgraph/_internal/_typing.py, TypedDictLikeV1 is defined as:

class TypedDictLikeV1(Protocol):
    __required_keys__: ClassVar[frozenset[str]]
    __optional_keys__: ClassVar[frozenset[str]]

Python's TypedDict metaclass provides __required_keys__ and __optional_keys__ as class-level frozenset[str] attributes. At runtime, this works perfectly. However, ty cannot statically verify that the metaclass-provided attributes satisfy the ClassVar[frozenset[str]] declared in the protocol.

Note: TypedDictLikeV2 (without ClassVar) exists in the same file but is not sufficient to resolve the issue, since ty still cannot match the metaclass-provided attributes against the plain frozenset[str] annotations either.

Current Workaround

builder = StateGraph(MyState)  # ty: ignore[invalid-argument-type]

Suggested Fix

This might be addressable by adjusting the protocol definitions in _typing.py, or by adding ty-specific overloads. The fact that both TypedDictLikeV1 and TypedDictLikeV2 exist suggests this has been a known friction point across type checkers.

Environment

  • langgraph: 1.0.7
  • ty: 0.0.17
  • Python: 3.13.11
  • OS: macOS (Darwin 25.3.0, aarch64)
Originally created by @5hal1n on GitHub (Feb 16, 2026). ## Description When using `ty` (Astral's type checker for Python), `StateGraph(MyState)` raises `invalid-argument-type` for any `TypedDict`-based state class. This is because `ty` cannot statically verify that Python's `TypedDict` satisfies the `TypedDictLikeV1` protocol. ## Reproduction ```python from typing import Annotated, TypedDict from langgraph.graph import StateGraph, add_messages from langchain_core.messages import BaseMessage class MyState(TypedDict, total=False): messages: Annotated[list[BaseMessage], add_messages] user_id: str builder = StateGraph(MyState) # ty error: invalid-argument-type ``` Running `ty check` produces: ``` error[invalid-argument-type]: Argument to bound method `__init__` is incorrect --> graph.py:9:22 | 9 | builder = StateGraph(MyState) | ^^^^^^^ Argument type `MyState` does not satisfy upper bound | `TypedDictLikeV1 | DataclassLike` of type variable `StateT` ``` ## Root Cause In [`langgraph/_internal/_typing.py`](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/_internal/_typing.py), `TypedDictLikeV1` is defined as: ```python class TypedDictLikeV1(Protocol): __required_keys__: ClassVar[frozenset[str]] __optional_keys__: ClassVar[frozenset[str]] ``` Python's `TypedDict` metaclass provides `__required_keys__` and `__optional_keys__` as class-level `frozenset[str]` attributes. At runtime, this works perfectly. However, `ty` cannot statically verify that the metaclass-provided attributes satisfy the `ClassVar[frozenset[str]]` declared in the protocol. Note: `TypedDictLikeV2` (without `ClassVar`) exists in the same file but is not sufficient to resolve the issue, since `ty` still cannot match the metaclass-provided attributes against the plain `frozenset[str]` annotations either. ## Current Workaround ```python builder = StateGraph(MyState) # ty: ignore[invalid-argument-type] ``` ## Suggested Fix This might be addressable by adjusting the protocol definitions in `_typing.py`, or by adding `ty`-specific overloads. The fact that both `TypedDictLikeV1` and `TypedDictLikeV2` exist suggests this has been a known friction point across type checkers. ## Environment - **langgraph**: 1.0.7 - **ty**: 0.0.17 - **Python**: 3.13.11 - **OS**: macOS (Darwin 25.3.0, aarch64)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#1151