pypa/pip · error · KeyError

No metadata except PKG-INFO is available

Error message

No metadata except PKG-INFO is available

What it means

Raised by FileMetadata.get_metadata when any metadata name other than 'PKG-INFO' is requested. FileMetadata is a minimal provider that wraps a single PKG-INFO file path and deliberately rejects all other metadata requests (entry_points.txt, requires.txt, etc.) with a KeyError. This is by design — FileMetadata only knows about one file.

Solutions

  1. Use PathMetadata or EggMetadata instead of FileMetadata — they support the full set of metadata files in an egg-info/dist-info directory.
  2. If you only need PKG-INFO data, always request 'PKG-INFO' specifically.
  3. Wrap calls in try/except KeyError when querying metadata from an unknown provider type.
  4. Point the metadata provider at the full egg-info or dist-info directory rather than a single PKG-INFO file.

Example fix

// before
from pkg_resources import FileMetadata, Distribution
md = FileMetadata('/path/to/PKG-INFO')
dist = Distribution(metadata=md)
dist.get_entry_map()  # KeyError: No metadata except PKG-INFO

// after
from pkg_resources import PathMetadata, Distribution
egg_info = '/path/to/Package.egg-info'
md = PathMetadata('/path/to', egg_info)
dist = Distribution.from_location('/path/to', 'Package.egg-info', metadata=md)
dist.get_entry_map()  # works
Defensive patterns

Strategy: try-catch

Validate before calling

from pkg_resources import FileMetadata
md = dist._provider if hasattr(dist, '_provider') else None
if isinstance(md, FileMetadata):
    # only PKG-INFO is available; avoid other metadata calls
    pass

Type guard

from pkg_resources import FileMetadata
def supports_full_metadata(provider) -> bool:
    return not isinstance(provider, FileMetadata)

Try / catch

try:
    dist.get_entry_map()
except KeyError:
    # FileMetadata or incomplete provider; skip entry point inspection
    entry_map = {}

Prevention

When it happens

Trigger: Calling get_metadata('requires.txt') or any non-PKG-INFO name on a Distribution whose provider is a FileMetadata instance. FileMetadata is constructed with a single file path (e.g. `FileMetadata('/path/to/PKG-INFO')`) and only returns data for 'PKG-INFO'.

Common situations: Manually constructing a Distribution with FileMetadata pointing at a lone PKG-INFO file and then calling get_entry_map() or requires(), which internally request other metadata files; tooling that inspects metadata on a partially-extracted or incomplete package.

Related errors


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

Appendix: source

Thrown at src/pip/_vendor/pkg_resources/__init__.py:2171

        metadata = FileMetadata("/path/to/PKG-INFO")

    This provider rejects all data and metadata requests except for PKG-INFO,
    which is treated as existing, and will be the contents of the file at
    the provided location.
    """

    def __init__(self, path: StrPath):
        self.path = path

    def _get_metadata_path(self, name):
        return self.path

    def has_metadata(self, name: str) -> bool:
        return name == 'PKG-INFO' and os.path.isfile(self.path)

    def get_metadata(self, name: str):
        if name != 'PKG-INFO':
            raise KeyError("No metadata except PKG-INFO is available")

        with open(self.path, encoding='utf-8', errors="replace") as f:
            metadata = f.read()
        self._warn_on_replacement(metadata)
        return metadata

    def _warn_on_replacement(self, metadata):
        replacement_char = '�'
        if replacement_char in metadata:
            tmpl = "{self.path} could not be properly decoded in UTF-8"
            msg = tmpl.format(**locals())
            warnings.warn(msg)

    def get_metadata_lines(self, name: str) -> Iterator[str]:
        return yield_lines(self.get_metadata(name))


class PathMetadata(DefaultProvider):

View on GitHub (pinned to f399c37189)