{"record":{"id":"b0afade11a9d59c2","repo":"pydantic/pydantic","slug":"you-should-use-typing-extensions-typeddict-inste-b0afad","errorCode":null,"errorMessage":"You should use `typing_extensions.TypedDict` instead of `typing.TypedDict` with Python < 3.11. Without it, there is no way to reflect Required/NotRequired keys.","messagePattern":"You should use `typing_extensions\\.TypedDict` instead of `typing\\.TypedDict` with Python < 3\\.11\\. Without it, there is no way to reflect Required/NotRequired keys\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pydantic/v1/annotated_types.py","lineNumber":44,"sourceCode":") -> Type['BaseModel']:\n    \"\"\"\n    Create a `BaseModel` based on the fields of a `TypedDict`.\n    Since `typing.TypedDict` in Python 3.8 does not store runtime information about optional keys,\n    we raise an error if this happens (see https://bugs.python.org/issue38834).\n    \"\"\"\n    field_definitions: Dict[str, Any]\n\n    # Best case scenario: with python 3.9+ or when `TypedDict` is imported from `typing_extensions`\n    if not hasattr(typeddict_cls, '__required_keys__'):\n        raise TypeError(\n            'You should use `typing_extensions.TypedDict` instead of `typing.TypedDict` with Python < 3.9.2. '\n            'Without it, there is no way to differentiate required and optional fields when subclassed.'\n        )\n\n    if is_legacy_typeddict(typeddict_cls) and any(\n        is_typeddict_special(t) for t in typeddict_cls.__annotations__.values()\n    ):\n        raise TypeError(\n            'You should use `typing_extensions.TypedDict` instead of `typing.TypedDict` with Python < 3.11. '\n            'Without it, there is no way to reflect Required/NotRequired keys.'\n        )\n\n    required_keys: FrozenSet[str] = typeddict_cls.__required_keys__  # type: ignore[attr-defined]\n    field_definitions = {\n        field_name: (field_type, Required if field_name in required_keys else None)\n        for field_name, field_type in typeddict_cls.__annotations__.items()\n    }\n\n    return create_model(typeddict_cls.__name__, **kwargs, **field_definitions)\n\n\ndef create_model_from_namedtuple(namedtuple_cls: Type['NamedTuple'], **kwargs: Any) -> Type['BaseModel']:\n    \"\"\"\n    Create a `BaseModel` based on the fields of a named tuple.\n    A named tuple can be created with `typing.NamedTuple` and declared annotations\n    but also with `collections.namedtuple`, in this case we consider all fields","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/pydantic/pydantic/blob/cc13d1b8c978eaf78ed5308329cd41f03ecc3144/pydantic/v1/annotated_types.py#L26-L62","documentation":"TypeError raised by pydantic.v1.create_model_from_typeddict when the TypedDict is a 'legacy' (PEP 589) TypedDict AND at least one annotation uses the special forms Required / NotRequired / ReadOnly. Those special forms are only reflectable on typing.TypedDict from Python 3.11 onward; on older runtimes pydantic v1 cannot tell which keys are required, so it asks the user to switch to typing_extensions.TypedDict. The check is is_legacy_typeddict(typeddict_cls) combined with any(is_typeddict_special(t) for t in __annotations__.values()).","triggerScenarios":"On Python < 3.11, calling create_model_from_typeddict on a typing.TypedDict subclass that uses Required[...] or NotRequired[...] (or ReadOnly[...]) as an annotation. The legacy TypedDict does not store the required/optional semantics for those special forms, so the guard raises TypeError.","commonSituations":"Migrating a TypedDict to use Required/NotRequired while the project still supports Python 3.10; CI matrix covering 3.10/3.9 while the dev worked on 3.12; mixing typing.TypedDict with typing_extensions.Required without also importing TypedDict from typing_extensions; dependency on a library that hands you a legacy TypedDict.","solutions":["Import TypedDict from typing_extensions (from typing_extensions import TypedDict) and keep using Required/NotRequired from typing_extensions.","Upgrade the runtime to Python >= 3.11 where typing.TypedDict reflects the special forms.","Drop Required/NotRequired from the TypedDict and encode optionality via total=False / total=True or separate TypedDicts.","Avoid create_model_from_typeddict for that class; build the model with create_model and explicit field definitions."],"exampleFix":"// before\nfrom typing import TypedDict\nfrom typing_extensions import Required, NotRequired\nfrom pydantic.v1 import create_model_from_typeddict\n\nclass User(TypedDict):\n    id: Required[int]\n    nickname: NotRequired[str]\n\nM = create_model_from_typeddict(User)  # TypeError on py<3.11\n\n// after\nfrom typing_extensions import TypedDict, Required, NotRequired\nfrom pydantic.v1 import create_model_from_typeddict\n\nclass User(TypedDict):\n    id: Required[int]\n    nickname: NotRequired[str]\n\nM = create_model_from_typeddict(User)","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"import typing, typing_extensions\n\ndef typeddict_supports_special_forms(typeddict_cls: type) -> bool:\n    # Safe when TypedDict comes from typing_extensions, or runtime is >= 3.11\n    is_ext = typeddict_cls is getattr(typing_extensions, 'TypedDict', object) or issubclass(typeddict_cls, getattr(typing_extensions, 'TypedDict', object))\n    return is_ext or sys.version_info >= (3, 11)","tryCatchPattern":"null","preventionTips":["When using Required/NotRequired/ReadOnly, import both TypedDict and those special forms from typing_extensions.","Keep the supported-Python floor at 3.11+ if you want to use typing.TypedDict with these special forms.","In shared libraries, gate Required/NotRequired usage behind a typing_extensions import unconditionally.","Lint against 'from typing import TypedDict' when targeting Python < 3.11."],"tags":["typeddict","required-notrequired","typing-extensions","python-version","pydantic-v1"],"backgroundTag":null,"analyzedSha":"cc13d1b8c978eaf78ed5308329cd41f03ecc3144","analyzedAt":"2026-08-11T16:38:52.905Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}