{"record":{"id":"e62f05973d0dfa16","repo":"zylon-ai/private-gpt","slug":"distribution-metadata-is-missing-name","errorCode":null,"errorMessage":"Distribution metadata is missing Name","messagePattern":"Distribution metadata is missing Name","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"scripts/build_pip_index.py","lineNumber":35,"sourceCode":"\n@dataclass(frozen=True)\nclass Distribution:\n    name: str\n    normalized_name: str\n    filename: str\n    requires_python: str | None\n    sha256: str\n\n\ndef normalize_name(name: str) -> str:\n    return re.sub(r\"[-_.]+\", \"-\", name).lower()\n\n\ndef parse_metadata(payload: str) -> tuple[str, str | None]:\n    metadata = Parser().parsestr(payload)\n    name = metadata[\"Name\"]\n    if not name:\n        raise ValueError(\"Distribution metadata is missing Name\")\n    return name, metadata.get(\"Requires-Python\")\n\n\ndef read_wheel_metadata(path: Path) -> tuple[str, str | None]:\n    with zipfile.ZipFile(path) as archive:\n        metadata_name = next(\n            name for name in archive.namelist() if name.endswith(\".dist-info/METADATA\")\n        )\n        return parse_metadata(archive.read(metadata_name).decode())\n\n\ndef read_sdist_metadata(path: Path) -> tuple[str, str | None]:\n    with tarfile.open(path, \"r:gz\") as archive:\n        pkg_info = next(\n            member\n            for member in archive.getmembers()\n            if member.name == \"PKG-INFO\" or member.name.endswith(\"/PKG-INFO\")\n        )","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/scripts/build_pip_index.py#L17-L53","documentation":"Raised by parse_metadata in scripts/build_pip_index.py when parsing a wheel's METADATA or an sdist's PKG-INFO email-header blob yields no 'Name:' field. Every compliant Python distribution must carry Name in its core metadata; if it is absent the file is malformed or truncated, and the index builder cannot attribute the artifact to a project, so it aborts.","triggerScenarios":"A hand-built wheel whose METADATA file lacks the Name header; a truncated/corrupted artifact produced by an interrupted build; a METADATA file with a BOM or wrong encoding that makes email.parser miss the header; an intentionally minimal test artifact passed to the script.","commonSituations":"Manually crafted or patched wheels for air-gapped pip indexes; artifacts produced by nonstandard build tools; partial uploads where the file was cut off; dist-info directory named correctly but populated with a stub METADATA.","solutions":["Rebuild the distribution with a standard backend (hatchling, setuptools, uv build) so METADATA/PKG-INFO are complete","Inspect the artifact: unzip -p file.whl '*.dist-info/METADATA' | head and confirm a 'Name:' line exists","Delete the malformed artifact from the package dir so the index build can proceed with valid ones","If the file is corrupted (size 0 / truncated), re-fetch or rebuild it"],"exampleFix":"# before: wheel METADATA contains only\nMetadata-Version: 2.1\n\n# after: rebuild properly\nuv build   # or: python -m build\nunzip -p dist/*.whl '*.dist-info/METADATA' | grep '^Name:'","handlingStrategy":"validation","validationCode":"import zipfile\n\ndef wheel_has_name(path: str) -> bool:\n    with zipfile.ZipFile(path) as z:\n        meta = next((n for n in z.namelist() if n.endswith(\".dist-info/METADATA\")), None)\n        if meta is None:\n            return False\n        return any(line.startswith(b\"Name:\") for line in z.read(meta).splitlines())","typeGuard":"null","tryCatchPattern":"try:\n    read_distribution(p)\nexcept ValueError as e:\n    logger.warning(\"skipping malformed artifact %s: %s\", p.name, e)\n    # continue with remaining artifacts instead of aborting the whole index build","preventionTips":["Only feed artifacts produced by standard build backends into the index script","Validate artifacts (unzip -p *.whl '*.dist-info/METADATA' | grep '^Name:') as a CI step","Delete zero-byte/truncated files from the package dir before building the index","Keep a regression check that rebuilds artifacts from source rather than hand-editing them"],"tags":["packaging","pip-index","metadata","scripts"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}