Skip to content

TypeError: unhashable type: 'list' when using dulwich 0.24.6 with Python <3.9.2 #1948

Closed

Description

@edmorley

Hi!

This may end up being wontfix (given it only affects older Python 3.9 patch versions), but filing for awareness / in case it helps others.

With the release of dulwich 0.24.6 our CI started failing with TypeError: unhashable type: 'list' errors when invoking Poetry with Python 3.9.0.

For example:
https://github.com/heroku/heroku-buildpack-python/actions/runs/18650476440/job/53167114670?pr=1941#step:5:544

I was able to reproduce this outside of Poetry - it affects Python 3.9.0 and 3.9.1 only (and not Python 3.9.2+).

For example:

$ docker run --rm python:3.9.1-slim bash -c 'pip install --disable-pip-version-check dulwich==0.24.6 && python -c "from dulwich import porcelain"'
Collecting dulwich==0.24.6
  Downloading dulwich-0.24.6-cp39-cp39-manylinux_2_28_aarch64.whl (1.3 MB)
Collecting urllib3>=2.2.2
  Downloading urllib3-2.5.0-py3-none-any.whl (129 kB)
Collecting typing_extensions>=4.0
  Downloading typing_extensions-4.15.0-py3-none-any.whl (44 kB)
Installing collected packages: urllib3, typing-extensions, dulwich
Successfully installed dulwich-0.24.6 typing-extensions-4.15.0 urllib3-2.5.0
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python3.9/site-packages/dulwich/porcelain.py", line 126, in <module>
    from .bisect import BisectState
  File "/usr/local/lib/python3.9/site-packages/dulwich/bisect.py", line 29, in <module>
    from dulwich.repo import Repo
  File "/usr/local/lib/python3.9/site-packages/dulwich/repo.py", line 66, in <module>
    from . import reflog, replace_me
  File "/usr/local/lib/python3.9/site-packages/dulwich/reflog.py", line 208, in <module>
    reachable_checker: Optional[Callable[[bytes], bool]] = None,
  File "/usr/local/lib/python3.9/typing.py", line 262, in inner
    return func(*args, **kwds)
  File "/usr/local/lib/python3.9/typing.py", line 339, in __getitem__
    return self._getitem(self, parameters)
  File "/usr/local/lib/python3.9/typing.py", line 463, in Optional
    return Union[arg, type(None)]
  File "/usr/local/lib/python3.9/typing.py", line 262, in inner
    return func(*args, **kwds)
  File "/usr/local/lib/python3.9/typing.py", line 339, in __getitem__
    return self._getitem(self, parameters)
  File "/usr/local/lib/python3.9/typing.py", line 451, in Union
    parameters = _remove_dups_flatten(parameters)
  File "/usr/local/lib/python3.9/typing.py", line 231, in _remove_dups_flatten
    return tuple(_deduplicate(params))
  File "/usr/local/lib/python3.9/typing.py", line 205, in _deduplicate
    all_params = set(params)
TypeError: unhashable type: 'list'

To resolve the error, one needs to either:

  • Downgrade dulwich to 0.24.5 or older
  • Or, upgrade Python 3.9.0/3.9.1 to Python 3.9.2 or newer

The typing usage that is tripping up the typing module is on this line:

reachable_checker: Optional[Callable[[bytes], bool]] = None,

And was introduced in this PR:
https://github.com/jelmer/dulwich/pull/1941/files#diff-d4672769f4e2861358cbfa19fdf0f71c481575deec25d702a93f96baecf5cf6cR208

Looking at the Python 3.9.2 release notes:
https://docs.python.org/3.9/whatsnew/changelog.html#python-3-9-2-final

...I see this entry:

bpo-42195: The args of the parameterized generics for typing.Callable and collections.abc.Callable are now consistent. The args for collections.abc.Callable are now flattened while typing.Callable’s have not changed. To allow this change, types.GenericAlias can now be subclassed and collections.abc.Callable’s class_getitem will now return a subclass of types.GenericAlias. Tests for typing were also updated to not subclass things like Callable[..., T] as that is not a valid base class. Finally, both types no longer validate their argtypes, in Callable[[argtypes], resulttype] to prepare for PEP 612. Patch by Ken Jin.

It seems like the relevant upstream CPython 3.9 change that resolves this issue, is that in the last sentence? ("both types no longer validate their argtypes") ie:

Additional context

The reason we have a test for Python 3.9.0, is that our tool (a buildpack) allows end users to pick arbitrary Python versions to install (similar to pyenv or GitHub Actions allowing people to pick their Python version) - and so to ensure backwards compatibility, we not only have tests for each supported Python package manager against the latest patch release of each major Python version (3.9-3.14), but also the oldest available Python version too (ie for Python 3.9 we test both 3.9.24 and 3.9.0). We're due to drop end-user support for Python 3.9 in January 2026.

Activity

  1. edmorley commented on Oct 21, 2025

    @edmorley
    Author

    So one possible workaround on the dulwich side, might be to:

    1. Adjust requires_python to be >=3.9.2 rather than >=3.9 (
      requires-python = ">=3.9"
      )
    2. Publish dulwich 0.24.7 with that change
    3. Then mark dulwich 0.24.6 as yanked on PyPI

    Doing this would mean a pip install dulwich on Python 3.9.0 / 3.9.1 would cause pip to automatically backtrack the dulwich package version back down to 0.24.5, without the need for end users knowing they need to explicitly specify dulwich<0.24.6. (Yanking doesn't delete the old version - anyone who pins explicitly to dulwich==0.24.6 will still be able to use it.)

    Would this be something you'd be open to? :-)

  2. added 2 commits that reference this issue on Oct 21, 2025
    03096ba
    81c8a65
  3. jelmer commented on Oct 21, 2025

    @jelmer
    Owner

    I'm inclined to just convert this type annotation to a string one for now, that should probably address it.

  4. jelmer commented on Oct 21, 2025

    @jelmer
    Owner

    @edmorley any chance you could test #1949 with python 3.9.0? I don't have easy access to Python 3.9.0 anymore unfortunately.

  5. added a commit that references this issue on Oct 21, 2025
    ee8e208
  6. edmorley commented on Oct 21, 2025

    @edmorley
    Author

    Thank you for the quick reply!

    #1949 fixes the error for me, when testing locally using Docker (and the non-slim Python image, which contains Git) and dulwich installed from the PR's branch :-)

    $ docker run --rm python:3.9.0 bash -c 'pip install --disable-pip-version-check "dulwich @ git+https://github.com/jelmer/dulwich@typing-workaround" && python -c "from dulwich import porcelain"'
    Collecting dulwich@ git+https://github.com/jelmer/dulwich@typing-workaround
      Cloning https://github.com/jelmer/dulwich (to revision typing-workaround) to /tmp/pip-install-f5gfqs91/dulwich_70e9ff1ce4c5412fab3499788ede33ab
      Installing build dependencies: started
      Installing build dependencies: finished with status 'done'
      Getting requirements to build wheel: started
      Getting requirements to build wheel: finished with status 'done'
      Installing backend dependencies: started
      Installing backend dependencies: finished with status 'done'
        Preparing wheel metadata: started
        Preparing wheel metadata: finished with status 'done'
    Collecting typing_extensions>=4.0
      Downloading typing_extensions-4.15.0-py3-none-any.whl (44 kB)
    Collecting urllib3>=2.2.2
      Downloading urllib3-2.5.0-py3-none-any.whl (129 kB)
    Building wheels for collected packages: dulwich
      Building wheel for dulwich (PEP 517): started
      Building wheel for dulwich (PEP 517): finished with status 'done'
      Created wheel for dulwich: filename=dulwich-0.24.7-cp39-cp39-linux_aarch64.whl size=538322 sha256=b06834ea956ff0ee29b18644a08caa354b2a3b38ff7a920da696339b5cf3ec37
      Stored in directory: /tmp/pip-ephem-wheel-cache-sl453ral/wheels/31/60/55/23be01292f4c0d233736bfa46a377c018eae2883cf15bf3f6a
    Successfully built dulwich
    Installing collected packages: urllib3, typing-extensions, dulwich
    Successfully installed dulwich-0.24.7 typing-extensions-4.15.0 urllib3-2.5.0
    
  7. jelmer commented on Oct 21, 2025

    @jelmer
    Owner

    Great, thanks for verifying!

  8. added a commit that references this issue on Oct 21, 2025
    21f709f
  9. added 2 commits that reference this issue on Oct 21, 2025
    9b59a49
    7a61c3a
  10. added 2 commits that reference this issue on Jan 8, 2026
    9ddc47c
    5c932ca
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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions