pypa/pip · error · InstallationError

For req: .

Error message

For req: {req_description}. {e.args[0]}

What it means

This is a generic error-context wrapper (the req_error_context context manager at wheel.py:738). It does not raise a new failure; it catches any InstallationError raised while installing a specific wheel and re-raises it with 'For req: <description>.' prepended, preserving the original cause via 'from e'. Its purpose is to attach the requirement identity to an otherwise opaque wheel-installation failure so the user knows which package broke.

Solutions

  1. Read the text AFTER 'For req: ...' in the message — that is the underlying InstallationError and the actual root cause to fix.
  2. Re-download the wheel (clear pip cache: pip cache purge) in case of a corrupt/partial download.
  3. Check filesystem permissions and free disk space in the target environment/site-packages.
  4. Retry with -v / --no-cache-dir to get the original traceback and pinpoint which install sub-step failed.

Example fix

# before: opaque failure during bulk install
pip install -r requirements.txt
# after: isolate the failing req and surface the real cause
pip install --no-cache-dir -v <the-single-failing-package>
Defensive patterns

Strategy: try-catch

Validate before calling

# No pre-API validation possible (it wraps arbitrary install failures).
# Validate the wheel file is a sound zip before handing to pip.
import zipfile, sys
for whl in sys.argv[1:]:
    if not zipfile.is_zipfile(whl):
        print(f"{whl} is not a valid zip/wheel"); sys.exit(1)
    bad = zipfile.ZipFile(whl).testzip()
    if bad is not None:
        print(f"{whl} has corrupt member: {bad}"); sys.exit(1)
print("wheels ok")

Type guard

import zipfile, os
from typing import TypeGuard

def is_installable_wheel(path: str) -> TypeGuard[str]:
    return (os.path.isfile(path)
            and path.endswith('.whl')
            and zipfile.is_zipfile(path)
            and zipfile.ZipFile(path).testzip() is None)

Try / catch

from subprocess import run, CalledProcessError
try:
    run(["pip", "install", whl], check=True)
except CalledProcessError as e:
    # 'For req: ...' is pip's own message; surface it to the caller.
    raise RuntimeError(f"wheel install failed for {whl}: {e}") from e

Prevention

When it happens

Trigger: Raised inside install_wheel/_install_wheel whenever the per-wheel install step (unzipping, copying files, compiling bytecode, writing RECORD) throws an InstallationError. The message you actually see is the ORIGINAL InstallationError text (e.args[0]) with the requirement description prefixed.

Common situations: Corrupt or malformed wheel files (missing RECORD, bad zip), permission errors writing into site-packages, .pyc compilation failures on read-only environments, or disk-full during file copy. Because it is a wrapper, the real problem is in the trailing portion of the message.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/d057f8b0f4c86c73. Report an issue: GitHub.

Appendix: source

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

    )

    # Record details of all files installed
    record_path = os.path.join(dest_info_dir, "RECORD")

    with _generate_file(record_path, **csv_io_kwargs("w")) as record_file:
        # Explicitly cast to typing.IO[str] as a workaround for the mypy error:
        # "writer" has incompatible type "BinaryIO"; expected "_Writer"
        writer = csv.writer(cast("IO[str]", record_file))
        writer.writerows(_normalized_outrows(rows))


@contextlib.contextmanager
def req_error_context(req_description: str) -> Generator[None, None, None]:
    try:
        yield
    except InstallationError as e:
        message = f"For req: {req_description}. {e.args[0]}"
        raise InstallationError(message) from e


def install_wheel(
    name: str,
    wheel_path: str,
    scheme: Scheme,
    req_description: str,
    pycompile: bool = True,
    warn_script_location: bool = True,
    direct_url: DirectUrl | None = None,
    requested: bool = False,
    script_executable: str | None = None,
) -> None:
    with ZipFile(wheel_path, allowZip64=True) as z:
        with req_error_context(req_description):
            _install_wheel(
                name=name,
                wheel_zip=z,

View on GitHub (pinned to f399c37189)