pypa/pip · error · BadMetadata

Bad metadata in (invalid metadata entry `version`)

Error message

Bad metadata in {dist} (invalid metadata entry `version`)

What it means

Raised as BadMetadata(dist, reason="invalid metadata entry `version`") from the Distribution.version property in _dists.py:168-176. After trying to parse the version from the info directory name and falling back to dist.version, pip calls parse_version(version); if that raises TypeError (version is None/non-string), it is wrapped as BadMetadata because a valid PEP 440 version string is mandatory.

Solutions

  1. Reinstall the package from a good source to restore a valid 'Version' in METADATA.
  2. Repair or delete the corrupt .dist-info directory under site-packages.
  3. When building, ensure the backend writes a valid PEP 440 version string.

Example fix

// before: METADATA missing Version
Metadata-Version: 2.1
Name: mypkg
// after
Metadata-Version: 2.1
Name: mypkg
Version: 1.0.0
Defensive patterns

Strategy: try-catch

Validate before calling

// Before reading a dist's version, sanity-check the Version field:
for d in importlib.metadata.distributions():
    v = d.metadata.get('Version')
    if not v:
        print('dist missing Version:', d)

Try / catch

from pip._internal.metadata.importlib._compat import BadMetadata
try:
    ver = dist.version
except BadMetadata as e:
    if 'version' in e.reason:
        # reinstall or skip the broken dist
        ...

Prevention

When it happens

Trigger: Accessing the .version property of an importlib-backed Distribution whose info dir has no version AND whose dist.version is None or not a string, so parse_version raises TypeError.

Common situations: A distribution whose METADATA lacks a 'Version' field; a malformed .dist-info directory name without a version segment; metadata damaged by a faulty installer.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/ed04b9353f04c36b. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_internal/metadata/importlib/_dists.py:176

    def installed_location(self) -> str | None:
        if self._installed_location is None:
            return None
        return normalize_path(str(self._installed_location))

    @property
    def canonical_name(self) -> NormalizedName:
        return get_dist_canonical_name(self._dist)

    @property
    def version(self) -> Version:
        try:
            version = (
                parse_name_and_version_from_info_directory(self._dist)[1]
                or self._dist.version
            )
            return parse_version(version)
        except TypeError:
            raise BadMetadata(self._dist, reason="invalid metadata entry `version`")

    @property
    def raw_version(self) -> str:
        return self.metadata["Version"]

    def is_file(self, path: InfoPath) -> bool:
        return self._dist.read_text(str(path)) is not None

    def iter_distutils_script_names(self) -> Iterator[str]:
        # A distutils installation is always "flat" (not in e.g. egg form), so
        # if this distribution's info location is NOT a pathlib.Path (but e.g.
        # zipfile.Path), it can never contain any distutils scripts.
        if not isinstance(self._info_location, pathlib.Path):
            return
        for child in self._info_location.joinpath("scripts").iterdir():
            yield child.name

    def read_text(self, path: InfoPath) -> str:

View on GitHub (pinned to f399c37189)