{"id":"4420e19b25be45b0","repo":"pypa/pip","slug":"invalid-sdist-filename-extension-must-be-tar-gz","errorCode":null,"errorMessage":"Invalid sdist filename (extension must be '.tar.gz' or '.zip'): {filename!r}","messagePattern":"Invalid sdist filename \\(extension must be '\\.tar\\.gz' or '\\.zip'\\): (.+?)","errorType":"validation","errorClass":"InvalidSdistFilename","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/utils.py","lineNumber":276,"sourceCode":"        with an sdist extension (``.zip`` or ``.tar.gz``), or if it does not\n        contain a dash separating the name and the version of the distribution.\n\n    >>> from packaging.utils import parse_sdist_filename\n    >>> from packaging.version import Version\n    >>> name, ver = parse_sdist_filename(\"foo-1.0.tar.gz\")\n    >>> name\n    'foo'\n    >>> ver == Version('1.0')\n    True\n\n    .. _Source distribution format: https://packaging.python.org/specifications/source-distribution-format/#source-distribution-file-name\n    \"\"\"\n    if filename.endswith(\".tar.gz\"):\n        file_stem = filename[: -len(\".tar.gz\")]\n    elif filename.endswith(\".zip\"):\n        file_stem = filename[: -len(\".zip\")]\n    else:\n        raise InvalidSdistFilename(\n            f\"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):\"\n            f\" {filename!r}\"\n        )\n\n    # We are requiring a PEP 440 version, which cannot contain dashes,\n    # so we split on the last dash.\n    name_part, sep, version_part = file_stem.rpartition(\"-\")\n    if not sep:\n        raise InvalidSdistFilename(f\"Invalid sdist filename: {filename!r}\")\n\n    name = canonicalize_name(name_part)\n\n    try:\n        version = Version(version_part)\n    except InvalidVersion as e:\n        raise InvalidSdistFilename(\n            f\"Invalid sdist filename (invalid version): {filename!r}\"\n        ) from e","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/packaging/utils.py#L258-L294","documentation":"Raised by `parse_sdist_filename(filename)` when the filename ends with neither `.tar.gz` nor `.zip`. These are the only two legal sdist archive extensions per the source-distribution format; the parser checks the extension first before extracting the stem.","triggerScenarios":"Passing a `.whl`, `.egg`, `.tar.bz2`, `.tgz`, or any extension other than `.tar.gz`/`.zip` to `parse_sdist_filename`.","commonSituations":"Dispatching all archive names through the sdist parser; a directory of mixed wheels/sdists; an artifact renamed without preserving the `.tar.gz`/`.zip` extension; legacy `.tgz` archives.","solutions":["Route by extension: call `parse_sdist_filename` only for `.tar.gz`/`.zip`.","Re-download or re-package the sdist into a supported archive format.","Pre-check `filename.endswith(('.tar.gz', '.zip'))` before parsing.","For `.tgz`, first normalize/rename to `.tar.gz`."],"exampleFix":"// before\nparse_sdist_filename('foo-1.0.whl')  # raises\n\n// after\nif filename.endswith(('.tar.gz', '.zip')):\n    name, ver = parse_sdist_filename(filename)\nelif filename.endswith('.whl'):\n    name, ver, build, tags = parse_wheel_filename(filename)\nelse:\n    raise ValueError(f\"unsupported archive: {filename!r}\")","handlingStrategy":"validation","validationCode":"def is_sdist_filename(filename: str) -> bool:\n    return filename.endswith(('.tar.gz', '.zip'))","typeGuard":"def is_sdist_filename(name: object) -> bool:\n    return isinstance(name, str) and name.endswith(('.tar.gz', '.zip'))","tryCatchPattern":"from pip._vendor.packaging.utils import parse_sdist_filename, InvalidSdistFilename\n\nif filename.endswith(('.tar.gz', '.zip')):\n    try:\n        name, ver = parse_sdist_filename(filename)\n    except InvalidSdistFilename:\n        skip(filename)\nelse:\n    # route to wheel parser or skip\n    pass","preventionTips":["Dispatch by extension before parsing: `.tar.gz`/`.zip` -> sdist, `.whl` -> wheel.","Preserve the original archive extension when copying/renaming sdists.","Normalize `.tgz` to `.tar.gz` before parsing."],"tags":["python","packaging","utils","sdist","filename"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}