zylon-ai/private-gpt · error · ValueError

Unable to read PKG-INFO from {path}

Error message

Unable to read PKG-INFO from {path}

What it means

Raised by read_sdist_metadata in scripts/build_pip_index.py when a .tar.gz sdist contains a PKG-INFO member (found by name) but tarfile.extractfile() returns None for it. extractfile returns None only for non-regular members (directories, symlinks, devices), meaning the archive has a PKG-INFO entry that is not a plain file - a structurally invalid sdist.

Source

Thrown at scripts/build_pip_index.py:56

def read_wheel_metadata(path: Path) -> tuple[str, str | None]:
    with zipfile.ZipFile(path) as archive:
        metadata_name = next(
            name for name in archive.namelist() if name.endswith(".dist-info/METADATA")
        )
        return parse_metadata(archive.read(metadata_name).decode())


def read_sdist_metadata(path: Path) -> tuple[str, str | None]:
    with tarfile.open(path, "r:gz") as archive:
        pkg_info = next(
            member
            for member in archive.getmembers()
            if member.name == "PKG-INFO" or member.name.endswith("/PKG-INFO")
        )
        fileobj = archive.extractfile(pkg_info)
        if fileobj is None:
            raise ValueError(f"Unable to read PKG-INFO from {path}")
        return parse_metadata(fileobj.read().decode())


def read_distribution(path: Path) -> Distribution:
    if path.suffix == ".whl":
        name, requires_python = read_wheel_metadata(path)
    elif path.name.endswith(".tar.gz"):
        name, requires_python = read_sdist_metadata(path)
    else:
        raise ValueError(f"Unsupported distribution format: {path.name}")

    return Distribution(
        name=name,
        normalized_name=normalize_name(name),
        filename=path.name,
        requires_python=requires_python,
        sha256=hashlib.sha256(path.read_bytes()).hexdigest(),
    )

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Rebuild the sdist from source with a standard tool (python -m build / uv build) so PKG-INFO is a regular file
  2. Inspect member types: tar -tvf dist.tar.gz | grep PKG-INFO (should start with '-', not 'l' or 'd')
  3. Remove the offending sdist from the package dir and keep only well-formed wheels if the sdist is not required
  4. If the archive is corrupted, re-download/re-generate it

Example fix

# before: PKG-INFO stored as symlink
lrwxrwxrwx ... pkg-0.1.0/PKG-INFO -> setup.cfg

# after: rebuilt archive has a regular file
-rw-r--r-- ... pkg-0.1.0/PKG-INFO
Defensive patterns

Strategy: validation

Validate before calling

import tarfile

def sdist_pkg_info_readable(path: str) -> bool:
    with tarfile.open(path, "r:gz") as t:
        for m in t.getmembers():
            if m.name == "PKG-INFO" or m.name.endswith("/PKG-INFO"):
                return m.isfile()  # must be a regular file
    return False

Type guard

null

Try / catch

try:
    name, rp = read_sdist_metadata(p)
except ValueError as e:
    logger.warning("skipping bad sdist %s: %s", p.name, e)
    continue  # keep wheels, drop malformed sdists

Prevention

When it happens

Trigger: An sdist where PKG-INFO is a symlink to another file inside the tarball; a directory literally named PKG-INFO; a crafted or corrupted archive with a wrong member type; archives produced by tools that store PKG-INFO as a link target.

Common situations: Repackaged or manually edited sdists for internal indexes; security-hardened builds that convert files to symlinks; corrupted downloads where member types got mangled; artifacts from exotic packaging tools.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/7a191f6c9b9d73ab. Report an issue: GitHub.