python-poetry/poetry · error · FileNotFoundError
METADATA not found in wheel
Error message
METADATA not found in wheel
What it means
Raised by Uploader._get_metadata() when a .whl zip is opened but no member matching <name>.dist-info/METADATA is found at the archive root. The METADATA file is the wheel's packaging metadata; its absence means the wheel is malformed and cannot be uploaded.
Source
Thrown at src/poetry/publishing/uploader.py:352
elif len(exts) >= 2 and "".join(exts[-2:]) == ".tar.gz":
return "sdist"
raise ValueError("Unknown distribution format " + "".join(exts))
@staticmethod
def _get_metadata(file: Path) -> RawMetadata:
if file.suffix == ".whl":
with zipfile.ZipFile(file) as z:
for name in z.namelist():
parts = Path(name).parts
if (
len(parts) == 2
and parts[1] == "METADATA"
and parts[0].endswith(".dist-info")
):
with z.open(name) as mf:
return parse_email(mf.read().decode("utf-8"))[0]
raise FileNotFoundError("METADATA not found in wheel")
elif file.suffixes[-2:] == [".tar", ".gz"]:
with tarfile.open(file, "r:gz") as tar:
for member in tar.getmembers():
parts = Path(member.name).parts
if (
len(parts) == 2
and parts[1] == "PKG-INFO"
and (pf := tar.extractfile(member))
):
return parse_email(pf.read().decode("utf-8"))[0]
raise FileNotFoundError("PKG-INFO not found in sdist")
raise ValueError(f"Unsupported file type: {file}")
def _is_file_exists_error(self, response: requests.Response) -> bool:
# based on https://github.com/pypa/twine/blob/a6dd69c79f7b5abfb79022092a5d3776a499e31b/twine/commands/upload.py#L32
status = response.status_codeView on GitHub (pinned to 92b74dcfe3)
Solutions
- Rebuild the wheel cleanly: `poetry build -f wheel` (or `python -m build --wheel`).
- Inspect the wheel contents with `unzip -l file.whl` to confirm a *.dist-info/METADATA exists.
- Do not hand-edit or rezip wheels; regenerate them from source.
- If the wheel came from elsewhere, discard it and rebuild from your project.
Example fix
// before: malformed wheel $ unzip -l dist/mypkg-1.0.0-py3-none-any.whl # no dist-info/METADATA FileNotFoundError: METADATA not found in wheel // after $ rm dist/*.whl $ poetry build -f wheel
Defensive patterns
Strategy: validation
Validate before calling
import zipfile
from pathlib import Path
def wheel_has_metadata(path: Path) -> bool:
with zipfile.ZipFile(path) as z:
return any(
len(Path(n).parts) == 2
and Path(n).parts[1] == "METADATA"
and Path(n).parts[0].endswith(".dist-info")
for n in z.namelist()
) Prevention
- Build wheels with a standard backend (poetry/hatchling/setuptools).
- Do not rezip or hand-edit wheels.
- Validate wheel contents (unzip -l) in CI before publishing.
- Discard suspect wheels and rebuild from source.
When it happens
Trigger: A .whl file is passed to _get_metadata (suffix .whl passes the type check) but the zip contents have no top-level *.dist-info/METADATA entry — a corrupt or hand-assembled wheel.
Common situations: A wheel built by a broken/custom build backend; a wheel repackaged incorrectly after editing; a truncated download; a wheel renamed to .whl but not actually a wheel; a wheel whose dist-info dir was stripped.
Related errors
- PKG-INFO not found in sdist
- Unknown metadata version: {dist.metadata_version}
- Archive ({file}) does not exist
- Unknown distribution format {exts}
- Invalid build config setting '{value}'. It must be a valid J
AI-assisted analysis of python-poetry/poetry@92b74dcfe3 (2026-08-04).
Data as JSON: /data/errors/1e08e4a815464be4.json.
Report an issue: GitHub.