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_fileView on GitHub (pinned to d7d0d0a394)
Solutions
- Open the wheel (it's a zip) and inspect entries under the *.data/ directory.
- Ensure every file under *.data/ is nested in a valid scheme-key subdirectory (purelib, platlib, headers, scripts, data).
- Rebuild the wheel with a standards-compliant backend (setuptools, hatchling, flit) and reinstall.
- 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
- Use a PEP 517 build backend to produce well-formed wheels.
- Validate wheel layout in CI before publishing.
- Never hand-edit wheels; rebuild from source.
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
- Unknown scheme key used in {wheel_path}: {scheme_key} (for f
- Invalid script entry point: {entry_point} - A callable suffi
- For req: {req_description}. {e.args[0]}
- Invalid script entry point name {entry.name!r}: the script w
- The wheel {wheel_path!r} has a file {target_path!r} trying t
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/d3ec188483da6b1b.json.
Report an issue: GitHub.