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
- Rebuild the sdist from source with a standard tool (python -m build / uv build) so PKG-INFO is a regular file
- Inspect member types: tar -tvf dist.tar.gz | grep PKG-INFO (should start with '-', not 'l' or 'd')
- Remove the offending sdist from the package dir and keep only well-formed wheels if the sdist is not required
- 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
- Build sdists with python -m build / uv build; never repackage by hand
- Audit archives with tar -tvf and require PKG-INFO to be a regular file ('-' type)
- Skip sdists entirely in the index if only wheels are needed
- Treat symlinked PKG-INFO as a build-tool defect and file/fix it upstream
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
- Distribution metadata is missing Name
- Unsupported distribution format: {path.name}
- No distributions found in {package_dir}
- Postgres node store dependencies are not installed. Install
- Postgres client dependencies are not installed. Install with
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/7a191f6c9b9d73ab.
Report an issue: GitHub.