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
- Use PathMetadata or EggMetadata instead of FileMetadata — they support the full set of metadata files in an egg-info/dist-info directory.
- If you only need PKG-INFO data, always request 'PKG-INFO' specifically.
- Wrap calls in try/except KeyError when querying metadata from an unknown provider type.
- 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
- Use PathMetadata with a full egg-info/dist-info directory instead of FileMetadata.
- Always check provider type before querying non-PKG-INFO metadata.
- Construct Distribution.from_location() rather than manually wiring FileMetadata.
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
- Duplicate entry point
- Entry points must be listed in groups
- Error decoding metadata for
- Error parsing entry points for
- Invalid section heading
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)