pypa/pip · error · InstallationError

Could not install locked package {project_name!r} from {lock

Error message

Could not install locked package {project_name!r} from {locked_link.comes_from!r}: {detail}

What it means

InstallationError raised in find_best_candidate when a package is being installed from a locked link (a pre-pinned file from a lockfile) but that link fails the link evaluator's acceptance checks (format control, release control, requires-python, yank, etc.). Because locked links are explicit user intent, pip errors rather than silently ignoring them.

Source

Thrown at src/pip/_internal/index/package_finder.py:902

        All versions found are returned as an InstallationCandidate list.

        See LinkEvaluator.evaluate_link() for details on which files
        are accepted.
        """
        if project_name in self._all_candidates:
            return self._all_candidates[project_name]

        link_evaluator = self.make_link_evaluator(project_name)

        if locked_link := self._locked_links.get(canonicalize_name(project_name)):
            # If a locked link is known for that project, do not check
            # index_urls nor find_links. We don't use get_install_candidate here,
            # because if a locked link is unsupported (due to format control,
            # release control or otherwise), we want to error out immediately
            # instead of ignoring it.
            result, detail = link_evaluator.evaluate_link(locked_link)
            if result != LinkType.candidate:
                raise InstallationError(
                    f"Could not install locked package {project_name!r} "
                    f"from {locked_link.comes_from!r}: {detail}"
                )
            self._all_candidates[project_name] = [
                InstallationCandidate(project_name, detail, locked_link, locked=True)
            ]
            return self._all_candidates[project_name]

        collected_sources = self._link_collector.collect_sources(
            project_name=project_name,
            candidates_from_page=functools.partial(
                self.process_project_url,
                link_evaluator=link_evaluator,
            ),
        )

        page_candidates_it = itertools.chain.from_iterable(
            source.page_candidates()

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Read {detail} to see why the evaluator rejected the locked link and address that specific reason first.
  2. Regenerate the lockfile on the target platform so the pinned artifact is actually compatible.
  3. Loosen format/release control flags that exclude the locked artifact (--no-binary / --only-binary / prerelease policy).
  4. If the locked version was yanked, update the lock to a non-yanked release.

Example fix

# before - lock pins cp39 wheel, you run cp311
# lockfile: somepkg==1.0 --hash=... (cp39 wheel)
pip install -r locked-requirements.txt

# after - regenerate lock for the current interpreter
pip-compile --python-version 3.11 requirements.in
Defensive patterns

Strategy: validation

Validate before calling

# validate a locked link will pass the evaluator before installing
from pip._internal.index.collector import LinkCollector
from pip._internal.models.target_python import TargetPython
# pseudo: evaluate_link(locked_link) must == LinkType.candidate
result, detail = link_evaluator.evaluate_link(locked_link)
if result.name != 'candidate':
    print('locked link will be rejected:', detail)

Type guard

def locked_link_accepted(link_evaluator, link) -> bool:
    from pip._internal.index.package_finder import LinkType
    result, _ = link_evaluator.evaluate_link(link)
    return result == LinkType.candidate

Try / catch

from pip._internal.exceptions import InstallationError
try:
    finder.find_best_candidate(project, req)
except InstallationError as e:
    if 'Could not install locked package' in str(e):
        # regenerate lock for this platform
        ...

Prevention

When it happens

Trigger: Reached when self._locked_links contains a Link for the canonical project name (set via add_locked_link, typically from a constraints/lockfile) and link_evaluator.evaluate_link(locked_link) returns anything other than LinkType.candidate - e.g. the locked wheel is for the wrong Python version, is yanked, or excluded by --only-binary.

Common situations: A lockfile pins a wheel that is incompatible with the current interpreter (requires-python mismatch); the locked file was yanked upstream; format-control flags (--no-binary/--only-binary) exclude the locked artifact; the locked URL is no longer reachable/acceptable.

Related errors


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