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
- Read {detail} to see why the evaluator rejected the locked link and address that specific reason first.
- Regenerate the lockfile on the target platform so the pinned artifact is actually compatible.
- Loosen format/release control flags that exclude the locked artifact (--no-binary / --only-binary / prerelease policy).
- 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
- Generate lockfiles per-target-platform so locked artifacts are compatible.
- Avoid --only-binary/--no-binary settings that exclude locked artifacts.
- Do not lock yanked files.
- Re-run the lock whenever the target interpreter changes.
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
- Multiple locked links provided for {project_name}: {self._lo
- No matching distribution found for {req}
- Editable requirements are not allowed as constraints
- Unnamed requirements are not allowed as constraints
- Editable requirements are not allowed as constraints
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/a1fefd2fb0d9c22d.json.
Report an issue: GitHub.