{"id":"1c050aca6ea4a852","repo":"pypa/pip","slug":"cannot-determine-sdist-filename","errorCode":null,"errorMessage":"Cannot determine sdist filename","messagePattern":"Cannot determine sdist filename","errorType":"validation","errorClass":"PylockValidationError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/pylock.py","lineNumber":466,"sourceCode":"    @classmethod\n    def _from_dict(cls, d: Mapping[str, Any]) -> Self:\n        package_sdist = cls(\n            name=_get(d, str, \"name\"),\n            upload_time=_get(d, datetime, \"upload-time\"),\n            url=_get(d, str, \"url\"),\n            path=_get(d, str, \"path\"),\n            size=_get(d, int, \"size\"),\n            hashes=_get_required_as(d, Mapping, _validate_hashes, \"hashes\"),  # type: ignore[type-abstract]\n        )\n        _validate_path_url(package_sdist.path, package_sdist.url)\n        return package_sdist\n\n    @property\n    def filename(self) -> str:\n        \"\"\"Get the filename of the sdist.\"\"\"\n        filename = self.name or _path_name(self.path) or _url_name(self.url)\n        if not filename:\n            raise PylockValidationError(\"Cannot determine sdist filename\")\n        return filename\n\n\n@dataclass(frozen=True, init=False)\nclass PackageWheel:\n    name: str | None = None\n    upload_time: datetime | None = None\n    url: str | None = None\n    path: str | None = None\n    size: int | None = None\n    hashes: Mapping[str, str]  # type: ignore[misc]\n\n    def __init__(\n        self,\n        *,\n        name: str | None = None,\n        upload_time: datetime | None = None,\n        url: str | None = None,","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/pylock.py#L448-L484","documentation":"Raised as PylockValidationError by PackageSdist.filename (a computed property) in packaging.pylock when none of name, path, or url is set, so the sdist filename cannot be derived. The filename is needed downstream for cross-checks (parse_sdist_filename) and for indexing.","triggerScenarios":"Constructing a PackageSdist with name=None and neither path nor url, then accessing .filename (e.g. via Package._from_dict's sdist cross-check at line ~617). Also reachable if path/url resolve to empty via _path_name/_url_name.","commonSituations":"A lockfile entry where the sdist table exists but all locator fields are blank; programmatic construction without setting any identifier.","solutions":["Set at least one of name (the filename), path, or url on the sdist entry.","Regenerate the lockfile so the resolver records the sdist URL or filename.","If constructing manually, pass name='pkg-1.0.tar.gz'.","Catch the error and skip/repair the malformed sdist entry."],"exampleFix":"# before\nPackageSdist(hashes={...})\n# after\nPackageSdist(name=\\\"pkg-1.0.tar.gz\\\", hashes={...})","handlingStrategy":"validation","validationCode":"def sdist_has_filename(sdist_entry: dict) -> bool:\n    return bool(sdist_entry.get('name') or sdist_entry.get('path') or sdist_entry.get('url'))","typeGuard":"def is_named_sdist(d) -> bool:\n    return bool(d.get('name') or d.get('path') or d.get('url'))","tryCatchPattern":"try:\n    _ = package.sdist.filename\nexcept PylockValidationError as e:\n    if 'Cannot determine sdist filename' in str(e):\n        sdist_entry['name'] = f'{pkg.name}-{pkg.version}.tar.gz'","preventionTips":["Set name, path, or url on every sdist entry.","Regenerate lockfiles so the resolver records the sdist URL.","Construct PackageSdist with name='pkg-1.0.tar.gz' in code.","Validate sdist entries have a locator before adding."],"tags":["pylock","pep771","sdist","validation"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}