pypa/pip · error · InstallationError

Unexpected file in {wheel_path}: {record_path!r}. .data dire

Error message

Unexpected file in {wheel_path}: {record_path!r}. .data directory contents should be named like: '<scheme key>/<path>'.

What it means

Raised as InstallationError at wheel.py:518-524 when a file path under the wheel's *.data directory cannot be split into the expected '<scheme key>/<subpath>' form (the normed path split on os.path.sep yields fewer than 3 parts, raising ValueError). This means a .data entry is missing its required scheme-key subdirectory.

Source

Thrown at src/pip/_internal/operations/install/wheel.py:524

            return ZipBackedFile(record_path, dest_path, zip_file)

        return make_root_scheme_file

    def data_scheme_file_maker(
        zip_file: ZipFile, scheme: Scheme
    ) -> Callable[[RecordPath], File]:
        scheme_paths = {key: getattr(scheme, key) for key in SCHEME_KEYS}

        def make_data_scheme_file(record_path: RecordPath) -> File:
            normed_path = os.path.normpath(record_path)
            try:
                _, scheme_key, dest_subpath = normed_path.split(os.path.sep, 2)
            except ValueError:
                message = (
                    f"Unexpected file in {wheel_path}: {record_path!r}. .data directory"
                    " contents should be named like: '<scheme key>/<path>'."
                )
                raise InstallationError(message)

            try:
                scheme_path = scheme_paths[scheme_key]
            except KeyError:
                valid_scheme_keys = ", ".join(sorted(scheme_paths))
                message = (
                    f"Unknown scheme key used in {wheel_path}: {scheme_key} "
                    f"(for file {record_path!r}). .data directory contents "
                    f"should be in subdirectories named with a valid scheme "
                    f"key ({valid_scheme_keys})"
                )
                raise InstallationError(message)

            dest_path = os.path.join(scheme_path, dest_subpath)
            assert_no_path_traversal(scheme_path, dest_path)
            return ZipBackedFile(record_path, dest_path, zip_file)

        return make_data_scheme_file

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Open the wheel (it's a zip) and inspect entries under the *.data/ directory.
  2. Ensure every file under *.data/ is nested in a valid scheme-key subdirectory (purelib, platlib, headers, scripts, data).
  3. Rebuild the wheel with a standards-compliant backend (setuptools, hatchling, flit) and reinstall.
  4. If third-party, pin to a version whose wheel is correctly structured.

Example fix

# before (wheel layout)
mypkg-1.0.data/cli_helper

# after
mypkg-1.0.data/scripts/cli_helper
Defensive patterns

Strategy: validation

Validate before calling

import zipfile, os
VALID_PREFIX = ".data" + os.sep

def validate_wheel_data_layout(whl):
    with zipfile.ZipFile(whl) as z:
        for n in z.namelist():
            head = n.split(os.sep, 1)[0]
            if head.endswith(".data"):
                rest = n.split(os.sep, 2)
                if len(rest) < 3:
                    raise ValueError(f".data file missing scheme key/path: {n}")

Type guard

def is_valid_data_path(record_path: str) -> bool:
    parts = record_path.split("/", 2)
    return len(parts) >= 3 and parts[0].endswith(".data")

Prevention

When it happens

Trigger: A wheel places a file directly under '<name>-<ver>.data/' with no scheme-key subdir, e.g. 'mypkg-1.0.data/README' instead of 'mypkg-1.0.data/scripts/README'. The split into ('.data', scheme_key, subpath) fails.

Common situations: A custom or hand-rolled wheel that doesn't follow the .data directory layout. A buggy build backend that emits stray files at the .data root. Older/non-standard packaging tools.

Related errors


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