mypy icon indicating copy to clipboard operation
mypy copied to clipboard

`KeyError: 'deprecated'` because of bad cache

Open injust opened this issue 1 year ago • 10 comments

Crash Report

I ran mypy in my venv and the cache somehow got into a bad state, leading to crashes until the cache was removed. I don't know what triggered this. If it matters, the mypy that caused the bad cache was installed with faster-cache.

Traceback

Traceback (most recent call last):
  File "[...]/.venv/bin/mypy", line 8, in <module>
    sys.exit(console_entry())
             ~~~~~~~~~~~~~^^
  File "[...]/.venv/lib/python3.13/site-packages/mypy/__main__.py", line 15, in console_entry
    main()
    ~~~~^^
  File "mypy/main.py", line 109, in main
  File "mypy/main.py", line 193, in run_build
  File "mypy/build.py", line 194, in build
  File "mypy/build.py", line 269, in _build
  File "mypy/build.py", line 2940, in dispatch
  File "mypy/build.py", line 3331, in process_graph
  File "mypy/build.py", line 3409, in process_fresh_modules
  File "mypy/build.py", line 2096, in load_tree
  File "mypy/nodes.py", line 402, in deserialize
  File "mypy/nodes.py", line 4058, in deserialize
  File "mypy/nodes.py", line 3999, in deserialize
  File "mypy/nodes.py", line 263, in deserialize
  File "mypy/nodes.py", line 3420, in deserialize
  File "mypy/nodes.py", line 4058, in deserialize
  File "mypy/nodes.py", line 3999, in deserialize
  File "mypy/nodes.py", line 263, in deserialize
  File "mypy/nodes.py", line 952, in deserialize
  File "mypy/nodes.py", line 879, in deserialize
KeyError: 'deprecated'

To Reproduce

repro.zip

unzip repro.zip
cd repro/
uv venv
source .venv/bin/activate.fish
uv pip install -r requirements.txt
mypy foo.py

Your Environment

  • Mypy version used: 1.14.1 (compiled: yes)
  • Mypy configuration options from mypy.ini (and other config files): strict = true
  • Python version used: 3.13.1
  • Operating system and version: macOS Sequoia 15.2

injust avatar Jan 15 '25 12:01 injust

Workaround if anyone else runs into this: pass --no-incremental to a mypy run and the full run will fix up the corrupted cache.

ncoghlan avatar Jan 27 '25 07:01 ncoghlan

Facing the same issue here. @ncoghlan thanks for the suggestion, though I get an error when passing --no-incremental - probably specific to my config: error: --install-types not supported with incremental mode disabled

I am using mypy through pre-commit, if anyone else has a similar config, would appreciate any workarounds! Thanks

harith-mindway avatar Feb 24 '25 09:02 harith-mindway

I am using mypy through pre-commit, if anyone else has a similar config, would appreciate any workarounds! Thanks

I also happen to be using mypy through pre-commit 🤔

injust avatar Feb 24 '25 09:02 injust

Thanks for providing the repro, @injust. I experimented with it but cannot reproduce the crash. The only difference that I am aware of is that I am working on Windows.

The deprecated decorator has been supported since Mypy 1.14. For each function definition (FuncDef), an attribute called "deprecated" (that handles the deprecation message or is None/null) should be available in the cache. However, this is not the case for any of the function definitions stored in tokenize.data.json. I randomly picked another file in the cache ( enum.data.json), and it contains information on "deprecated" for the function definitions I checked.

The data_mtime information of all cached files:

{'1736325097': ['_frozen_importlib', '_frozen_importlib_external', '_io'],
 '1736939877': ['tokenize'],
 '1736939880': ['token'],
 '1736940420': ['abc',
                'ast',
                'builtins',
                'codecs',
                'contextlib',
                'dataclasses',
                'enum',
                'genericpath',
                'io',
                'pathlib',
                'posixpath',
                're',
                'resource',
                'sre_compile',
                'sre_constants',
                'sre_parse',
                'subprocess',
                'types',
                'typing',
                'typing_extensions',
                'warnings',
                '_ast',
                '_codecs',
                '_collections_abc',
                '_warnings']}

I cannot imagine a way how the serialisation of a function definition could be incomplete in such a way because the related method returns either a complete dictionary or nothing:

https://github.com/python/mypy/blob/5081c59b9c0c7ebe7070c62a4aeaf3d0de203a24/mypy/nodes.py#L860-L876

It's hard to tell what went wrong for me. My only idea is that tokenize.data.json could have been created by an older Mypy version and was not updated when a newer one was applied. Not very likely, I guess.

Are there any hints on how the cash became corrupted?

(@hauntsaninja: Do you think something like this could happen when switching between versions with fast-cache enabled and disabled?)

tyralla avatar Jun 14 '25 10:06 tyralla

I (used to) run mypy through the command-line (installed in my venv) and also through pre-commit (as a commit hook or pre-commit run -a), but I'm not sure running through pre-commit uses/modifies the same .mypy_cache/ directory.

Perhaps using both and/or their versions being out of sync could have caused this problem?

injust avatar Jun 14 '25 10:06 injust

Maybe. I don't know.

Does the crash still occur with Mypy 1.15 and 1.16?

tyralla avatar Jun 14 '25 11:06 tyralla

Does the crash still occur with Mypy 1.15 and 1.16?

No, at least I haven't run into this crash since I reported it.

injust avatar Jun 14 '25 15:06 injust

@ncoghlan @harith-mindway @tomasvotava @victorbadenas

Can you confirm the problem went away for (unknown) reasons? I think we could close this issue, then.

tyralla avatar Jun 14 '25 16:06 tyralla

Well the problem still appears from time to time, but deleting .mypy_cache always helps.

tomasvotava avatar Jun 14 '25 17:06 tomasvotava

And it is always because of KeyError: 'deprecated'? (And eventually only happens when analysing tokenize or other specific modules?)

tyralla avatar Jun 14 '25 17:06 tyralla

I don't only get the KeyError: 'deprecated' error from time to time but I also get a KeyError: 'is_bound' error from time to time. Removing .mypy_cache always helps, yes.

victorbadenas avatar Jun 25 '25 14:06 victorbadenas

Really is_bound? This was committed very recently in #19233 and is only included in Mypy 1.16.1. So similar to deprecated, which was first included in Mypy 1.14, released just before this issue was opened. This settles my impression that different Mypy versions are being used, and the newer one attempts to reuse the cache of the older one. Does this interpretation fit your workflow?

In case you use https://github.com/pre-commit/mirrors-mypy. There is a warning about using --install-types:

Note that using the --install-types is problematic. Mutating the pre-commit environment at runtime breaks cache and will break parallel builds.

tyralla avatar Jun 26 '25 04:06 tyralla

correct, I am using mirrors-mypy, v1.16.1 however I am not using the --install-types flag. It looks like additional_dependencies should be the culprit of that... Not running parallel builds though...

My current pre-commit hook

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.16.1
    hooks:
      - id: mypy
        additional_dependencies:
          - types-aioboto3
          - types-pyYAML

victorbadenas avatar Jun 26 '25 17:06 victorbadenas