Skip to content

Plugin crashes on Annotated[NotRequired[...], ...] TypedDict fields (get_proper_type given RequiredType) #3658

Open

Description

@novucs

Bug report

What's wrong

With the mypy plugin enabled, mypy crashes with an INTERNAL ERROR on any TypedDict field of the form Annotated[NotRequired[T], metadata]. Plain mypy accepts the same file. The pattern is common in langgraph-style state schemas (Annotated[NotRequired[list[X]], reducer]), so any project that imports langchain.agents or deepagents alongside the plugin crashes while mypy analyses those packages' own source.

Minimal reproduction, no Django imports needed:

from typing import Annotated, NotRequired, TypedDict


def keep_last(left: list[str], right: list[str]) -> list[str]:
    return right


class State(TypedDict):
    items: Annotated[NotRequired[list[str]], keep_last]
[tool.mypy]
plugins = ["mypy_django_plugin.main"]

[tool.django-stubs]
django_settings_module = "settings"
repro.py:8: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
version: 2.3.1
Traceback (most recent call last):
  File "mypy/semanal_typeddict.py", line 517, in analyze_typeddict_classdef_fields
  File "mypy/semanal.py", line 7897, in anal_type
  File "mypy/typeanal.py", line 357, in visit_unbound_type_nonoptional
  File "mypy_django_plugin/transformers/models.py", line 1122, in handle_annotated_type
    type_arg = get_proper_type(ctx.api.analyze_type(args[0]))
  File "mypy/types.py", line 3768, in get_proper_type
TypeError: mypy.types.ProperType object expected; got mypy.types.RequiredType

Cause: get_type_analyze_hook claims every typing.Annotated / typing_extensions.Annotated, so handle_annotated_type runs instead of mypy's own Annotated handling. Inside a TypedDict body ctx.api.analyze_type(NotRequired[...]) returns mypy's transient RequiredType, which is not a ProperType, and get_proper_type raises. The same code is on master and in 6.1.1.

How is that should be

The hook should leave TypedDict special forms alone so mypy's TypedDict analyser can consume them, for example by returning the analysed type unchanged when it is a RequiredType (and likewise ReadOnlyType) before calling get_proper_type. Non-Django Annotated fields would then behave exactly as they do without the plugin.

System information

  • OS: macOS 15
  • python version: 3.13.3
  • django version: 6.1
  • mypy version: 2.3.1
  • django-stubs version: 6.1.0 (function unchanged in 6.1.1 and master)
  • django-stubs-ext version: 6.0.7

Activity

  1. UnknownPlatypus commented on Sep 15, 2026

    @UnknownPlatypus
    Contributor

    I think this might be related to #893 and more generally to the handling of our custom Annotated

  2. added a commit that references this issue on Sep 26, 2026
    b83a812
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions