Skip to content

mypy errors on self: Annotated[Self, "tag"] #21917

Description

@Moussa-Mikhail

Bug Report

self: Self (unwrapped) is accepted with no error. The same Self, wrapped in
Annotated — e.g. self: Annotated[Self, "tag"] — raises Method cannot have explicit self annotation and Self type [misc].

Per [PEP 593](https://peps.python.org/pep-0593/), Annotated[T, x] is specified to be
treated identically to T by any tool that doesn't specifically interpret the
metadata:

If a tool or library does not support annotating an object with Annotated, it
should ignore it and treat the underlying type as the type of the object.

Since mypy doesn't itself interpret arbitrary Annotated metadata, wrapping Self
this way shouldn't change whether the explicit self-annotation is accepted — but it
does.

To Reproduce

from typing import Self, Annotated

class Foo:
    # OK -- no error
    def works(self: Self, x: int) -> None:
        pass

    # error: Method cannot have explicit self annotation and Self type  [misc]
    def fails(self: Annotated[Self, "tag"], x: int) -> None:
        pass

Expected Behavior

Both methods should be treated the same — either both accepted, or both rejected with
the same diagnostic. Annotated[Self, ...] should not behave differently from bare
Self in this position.

Actual Behavior

example.py:9: error: Method cannot have explicit self annotation and Self type  [misc]

The error appears only on the Annotated-wrapped version; the identical unwrapped
self: Self on the method directly above is accepted with no diagnostic at all.

Your Environment

  • Mypy version used: 2.3.1 (compiled: yes)
  • Mypy command-line flags: none (default settings)
  • Mypy configuration options: none (no mypy.ini/pyproject.toml config in the
    reproduction environment)
  • Python version used: 3.13.4
  • Operating system and version: openSUSE Tumbleweed v.20260829. Kernel: 7.2.0-1-default

Behavior in other type checkers

For comparison, the identical self: Annotated[Self, "tag"] construct was tested against two other checkers on the same file:

ty (Astral) accepts it with no error, and correctly treats self as generically Self-typed — reveal_type(Foo.fails) shows def fails[Self](self: Self, x: int) -> None, identical genericity to the accepted bare-Self case.
pyright does not raise an error either, but is a weaker counterexample: it doesn't just omit the metadata, it discards the annotation's type entirely — reveal_type shows self: Foo (the concrete class), not self: Self, i.e. it silently reverts to ordinary implicit self-typing as if the explicit annotation were never written.

Additional notes

This report was drafted with the assistance of an LLM (Claude). All claims in it — the reproduction, the exact error text, the version numbers, and the cross-checker comparison — were independently verified by running mypy, ty, and pyright directly against the code shown above; none of it is unverified model output. Happy to answer follow-up questions or run further variations on request.

This was noticed while trying to attach custom static-analysis metadata to a method's receiver type via Annotated[Self, MyCustomTag()], specifically because Annotated is documented as the mechanism for doing exactly this without affecting how standard type checkers see the underlying type. The current behavior means that use case isn't available for self specifically, even though it works normally for every other parameter position.

Activity

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

    bugmypy got something wrong

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions