Skip to content

Python 3.14.1+ annotationlib regression: ForwardRef.__hash__ raises TypeError: unhashable type: 'cell' #143831

@abhinand-c

Description

@abhinand-c

Bug report

Bug description:

This issue was originally reported in the beartype library (Ref: beartype/beartype#610), but investigation suggests it may stem from a change in Python’s annotationlib.ForwardRef implementation.

Starting with Python 3.14.1, deferred annotations (PEP 649) involving self-referential return type is raising: TypeError: unhashable type: 'cell' at decoration time. This worked correctly in Python 3.14.0 and the issue appears to persist in 3.14.2, suggesting a regression.

The error originates from annotationlib.ForwardRef.__hash__, which attempts to hash internal state containing non-hashable cell objects. Although observed via beartype, this may affects any downstream library that hashes ForwardRef objects. The following code seems to be raising the issue:
tuple(sorted(self.__cell__.items())) if isinstance(self.__cell__, dict) else self.__cell__,

def __hash__(self):
return hash((
self.__forward_arg__,
self.__forward_module__,
id(self.__globals__), # dictionaries are not hashable, so hash by identity
self.__forward_is_class__,
tuple(sorted(self.__cell__.items())) if isinstance(self.__cell__, dict) else self.__cell__,
self.__owner__,
tuple(sorted(self.__extra_names__.items())) if self.__extra_names__ else None,
))


Code:

#!pip install beartype==0.22.9

from beartype import beartype

class MyClass:
    @beartype
    def foo(self) -> MyClass:
        return MyClass()

print(MyClass().foo())

Observed behavior:

The program fails during decoration with the error: TypeError: unhashable type: 'cell'

File ".../beartype/_check/metadata/hint/hintsane.py", line 242, in __init__
    self._hash = hash((hint, hint_recursable_to_depth, typearg_to_hint))
File ".../python3.14/annotationlib.py", line 291, in __hash__
    return hash((..., tuple(sorted(self.__extra_names__.items()))))
TypeError: unhashable type: 'cell'

Inspection shows:

>>> self.__cell__
{'__classdict__': <cell at 0x...: dict object>}
>>> tuple(sorted(self.__cell__.items()))
(('__classdict__', <cell at 0x...>),)

Since cell objects are not hashable, this causes hash to fail.

Affected Versions:

Python 3.14.1 and 3.14.2
OS Tested on: MacOS

CPython versions tested on:

3.14

Operating systems tested on:

macOS

Linked PRs

Metadata

Metadata

Assignees

Labels

3.14bugs and security fixes3.15new features, bugs and security fixesstdlibStandard Library Python modules in the Lib/ directorytopic-typingtype-bugAn unexpected behavior, bug, or error

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions