pypa/pip · error · InvalidSdistFilename
Invalid sdist filename (extension must be '.tar.gz' or '.zip
Error message
Invalid sdist filename (extension must be '.tar.gz' or '.zip'): {filename!r} What it means
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.
Source
Thrown at src/pip/_vendor/packaging/utils.py:276
with an sdist extension (``.zip`` or ``.tar.gz``), or if it does not
contain a dash separating the name and the version of the distribution.
>>> from packaging.utils import parse_sdist_filename
>>> from packaging.version import Version
>>> name, ver = parse_sdist_filename("foo-1.0.tar.gz")
>>> name
'foo'
>>> ver == Version('1.0')
True
.. _Source distribution format: https://packaging.python.org/specifications/source-distribution-format/#source-distribution-file-name
"""
if filename.endswith(".tar.gz"):
file_stem = filename[: -len(".tar.gz")]
elif filename.endswith(".zip"):
file_stem = filename[: -len(".zip")]
else:
raise InvalidSdistFilename(
f"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):"
f" {filename!r}"
)
# We are requiring a PEP 440 version, which cannot contain dashes,
# so we split on the last dash.
name_part, sep, version_part = file_stem.rpartition("-")
if not sep:
raise InvalidSdistFilename(f"Invalid sdist filename: {filename!r}")
name = canonicalize_name(name_part)
try:
version = Version(version_part)
except InvalidVersion as e:
raise InvalidSdistFilename(
f"Invalid sdist filename (invalid version): {filename!r}"
) from eView on GitHub (pinned to d7d0d0a394)
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`.
Example fix
// before
parse_sdist_filename('foo-1.0.whl') # raises
// after
if filename.endswith(('.tar.gz', '.zip')):
name, ver = parse_sdist_filename(filename)
elif filename.endswith('.whl'):
name, ver, build, tags = parse_wheel_filename(filename)
else:
raise ValueError(f"unsupported archive: {filename!r}") Defensive patterns
Strategy: validation
Validate before calling
def is_sdist_filename(filename: str) -> bool:
return filename.endswith(('.tar.gz', '.zip')) Type guard
def is_sdist_filename(name: object) -> bool:
return isinstance(name, str) and name.endswith(('.tar.gz', '.zip')) Try / catch
from pip._vendor.packaging.utils import parse_sdist_filename, InvalidSdistFilename
if filename.endswith(('.tar.gz', '.zip')):
try:
name, ver = parse_sdist_filename(filename)
except InvalidSdistFilename:
skip(filename)
else:
# route to wheel parser or skip
pass Prevention
- 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.
When it happens
Trigger: Passing a `.whl`, `.egg`, `.tar.bz2`, `.tgz`, or any extension other than `.tar.gz`/`.zip` to `parse_sdist_filename`.
Common situations: 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.
Related errors
- Invalid sdist filename: {filename!r}
- Invalid wheel filename (extension must be '.whl'): {filename
- Invalid wheel filename (wrong number of parts): {filename!r}
- Invalid project name: {filename!r}
- Invalid build number: {build_part} in {filename!r}
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/4420e19b25be45b0.json.
Report an issue: GitHub.