{"id":"08b6a51e7d92a4f8","repo":"python-poetry/poetry","slug":"pkg-info-not-found-in-sdist","errorCode":null,"errorMessage":"PKG-INFO not found in sdist","messagePattern":"PKG-INFO not found in sdist","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"src/poetry/publishing/uploader.py","lineNumber":364,"sourceCode":"                        len(parts) == 2\n                        and parts[1] == \"METADATA\"\n                        and parts[0].endswith(\".dist-info\")\n                    ):\n                        with z.open(name) as mf:\n                            return parse_email(mf.read().decode(\"utf-8\"))[0]\n            raise FileNotFoundError(\"METADATA not found in wheel\")\n\n        elif file.suffixes[-2:] == [\".tar\", \".gz\"]:\n            with tarfile.open(file, \"r:gz\") as tar:\n                for member in tar.getmembers():\n                    parts = Path(member.name).parts\n                    if (\n                        len(parts) == 2\n                        and parts[1] == \"PKG-INFO\"\n                        and (pf := tar.extractfile(member))\n                    ):\n                        return parse_email(pf.read().decode(\"utf-8\"))[0]\n            raise FileNotFoundError(\"PKG-INFO not found in sdist\")\n\n        raise ValueError(f\"Unsupported file type: {file}\")\n\n    def _is_file_exists_error(self, response: requests.Response) -> bool:\n        # based on https://github.com/pypa/twine/blob/a6dd69c79f7b5abfb79022092a5d3776a499e31b/twine/commands/upload.py#L32\n        status = response.status_code\n        reason = response.reason.lower()\n        text = response.text.lower()\n        reason_and_text = reason + text\n\n        return (\n            # pypiserver (https://pypi.org/project/pypiserver)\n            status == 409\n            # PyPI / TestPyPI / GCP Artifact Registry\n            or (status == 400 and \"already exist\" in reason_and_text)\n            # Nexus Repository OSS (https://www.sonatype.com/nexus-repository-oss)\n            or (status == 400 and \"updating asset\" in reason_and_text)\n            or (status == 400 and \"cannot be updated\" in reason_and_text)","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/python-poetry/poetry/blob/92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54/src/poetry/publishing/uploader.py#L346-L382","documentation":"Raised by Uploader._get_metadata() when a .tar.gz sdist is opened but no top-level <name>-<version>/PKG-INFO member is found. PKG-INFO is the sdist's metadata file; its absence means the sdist is malformed. This blocks upload because metadata cannot be extracted.","triggerScenarios":"A .tar.gz sdist is processed (suffixes .tar.gz pass the type check) but the archive contains no PKG-INFO at the expected two-part path — e.g. a tarball that is not a real Python sdist, or one whose top-level dir was restructured.","commonSituations":"A tarball repackaged with a different top-level directory layout; a sdist whose PKG-INFO was stripped; a .tar.gz that is source code but not a proper sdist; a build backend bug that omitted PKG-INFO.","solutions":["Rebuild the sdist: `poetry build -f sdist` (or `python -m build --sdist`).","Inspect with `tar tzf file.tar.gz` to confirm a top-level <pkg>-<ver>/PKG-INFO entry.","Avoid rezipping or restructuring sdist tarballs; regenerate from source.","Verify the build backend produces PEP 517-compliant sdists."],"exampleFix":"// before: sdist missing PKG-INFO\n$ tar tzf dist/mypkg-1.0.0.tar.gz  # no PKG-INFO\nFileNotFoundError: PKG-INFO not found in sdist\n\n// after\n$ rm dist/*.tar.gz\n$ poetry build -f sdist","handlingStrategy":"validation","validationCode":"import tarfile\nfrom pathlib import Path\n\ndef sdist_has_pkg_info(path: Path) -> bool:\n    with tarfile.open(path, \"r:gz\") as tar:\n        return any(\n            len(Path(m.name).parts) == 2 and Path(m.name).parts[1] == \"PKG-INFO\"\n            for m in tar.getmembers()\n        )","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build sdists with a PEP 517 backend that emits PKG-INFO.","Do not restructure sdist tarballs after building.","Inspect sdist contents (tar tzf) in CI before publishing.","Rebuild suspect sdists from source."],"tags":["publishing","sdist","metadata","build"],"analyzedSha":"92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54","analyzedAt":"2026-08-04T20:33:34.072Z","schemaVersion":2}