pypa/pip · error · InvalidSdistFilename

Invalid sdist filename: {filename!r}

Error message

Invalid sdist filename: {filename!r}

What it means

Raised by `parse_sdist_filename` when, after stripping the `.tar.gz`/`.zip` extension, `file_stem.rpartition('-')` finds no dash at all (`sep == ''`). A valid sdist filename must contain at least one dash separating the project name from the version (e.g. `foo-1.0`). With no dash there is no name/version boundary to split on.

Source

Thrown at src/pip/_vendor/packaging/utils.py:285

    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 e

    return (name, version)

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Rename the file to the standard `name-version.tar.gz` (or `.zip`) form.
  2. Rebuild the sdist with a compliant backend, which always emits `name-version`.
  3. Pre-validate that the stem contains a dash before calling.
  4. If you only have a name and version separately, construct the `Version` directly instead of parsing a filename.

Example fix

// before
parse_sdist_filename('fooonly.tar.gz')  # no dash -> raises

// after
parse_sdist_filename('fooonly-1.0.tar.gz')
Defensive patterns

Strategy: validation

Validate before calling

def has_name_version_dash(filename: str) -> bool:
    if filename.endswith('.tar.gz'):
        stem = filename[:-len('.tar.gz')]
    elif filename.endswith('.zip'):
        stem = filename[:-len('.zip')]
    else:
        return False
    return '-' in stem

Type guard

def is_splitable_sdist(filename: object) -> bool:
    if not isinstance(filename, str):
        return False
    if filename.endswith('.tar.gz'):
        stem = filename[:-7]
    elif filename.endswith('.zip'):
        stem = filename[:-4]
    else:
        return False
    return '-' in stem

Try / catch

from pip._vendor.packaging.utils import parse_sdist_filename, InvalidSdistFilename

try:
    name, ver = parse_sdist_filename(filename)
except InvalidSdistFilename as e:
    if 'Invalid sdist filename:' in str(e) and 'extension' not in str(e):
        # no dash; reconstruct name-version from metadata
        ...
    raise

Prevention

When it happens

Trigger: A filename like `foobar.tar.gz` (no dash), or any single-token stem; the parser cannot tell where the name ends and the version begins.

Common situations: A malformed/renamed sdist; a project with no version embedded in the filename; an artifact whose name was collapsed.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/b9b482cf29bc2989.json. Report an issue: GitHub.