{"record":{"id":"3f3f7751e47b8e4d","repo":"pypa/pip","slug":"multiple-locked-links-provided-for-project-name","errorCode":null,"errorMessage":"Multiple locked links provided for {project_name}: {self._locked_links[project_name]} and {locked_link}","messagePattern":"Multiple locked links provided for (.+?): (.+?) and (.+?)","errorType":"exception","errorClass":"InstallationError","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/index/package_finder.py","lineNumber":1103,"sourceCode":"            logger.debug(\n                \"Using version %s (newest of versions: %s)\",\n                best_candidate.version,\n                _format_versions(best_candidate_result.applicable_candidates),\n            )\n            return best_candidate\n\n        # We have an existing version, and its the best version\n        logger.debug(\n            \"Installed version (%s) is most up-to-date (past versions: %s)\",\n            installed_version,\n            _format_versions(best_candidate_result.applicable_candidates),\n        )\n        raise BestVersionAlreadyInstalled\n\n    def add_locked_link(self, project_name: NormalizedName, locked_link: Link) -> None:\n        assert not self._all_candidates\n        if project_name in self._locked_links:\n            raise InstallationError(\n                f\"Multiple locked links provided for {project_name}: \"\n                f\"{self._locked_links[project_name]} and {locked_link}\"\n            )\n\n        self._locked_links[project_name] = locked_link\n\n\ndef _find_name_version_sep(fragment: str, canonical_name: str) -> int:\n    \"\"\"Find the separator's index based on the package's canonical name.\n\n    :param fragment: A <package>+<version> filename \"fragment\" (stem) or\n        egg fragment.\n    :param canonical_name: The package's canonical name.\n\n    This function is needed since the canonicalized name does not necessarily\n    have the same length as the egg info's name part. An example::\n\n    >>> fragment = 'foo__bar-1.0'","sourceCodeStart":1085,"sourceCodeEnd":1121,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_internal/index/package_finder.py#L1085-L1121","documentation":"Raised by CandidateEvaluator.add_locked_link (package_finder.py:1103) when a second locked link is registered for the same canonical project name. Locks must be unique per project, so a duplicate is treated as an inconsistent resolution set rather than silently overwriting the first.","triggerScenarios":"Calling add_locked_link twice for the same project_name (after the first has been stored in self._locked_links), or feeding a lock/resolution file that contains two distinct entries resolving to the same canonicalized project name.","commonSituations":"A requirements/lock file that lists the same package twice under different aliases/casings that canonicalize to one name (e.g. 'Flask' and 'flask'); merging two lock files naively; a tool that emits duplicate locked entries.","solutions":["De-duplicate the lock/resolution input so each canonical project name appears exactly once.","Canonicalize names (pip._vendor.packaging.utils.canonicalize_name) before building the locked-link set to catch alias collisions early.","If two entries are intentional, decide which link wins and remove the other."],"exampleFix":"// before\nflask==3.0.0\nFlask==2.3.3\n// after (single canonical entry)\nflask==3.0.0","handlingStrategy":"validation","validationCode":"// Canonicalize and de-duplicate locked entries before building the lock set:\nfrom pip._vendor.packaging.utils import canonicalize_name\nseen = {}\nfor name, link in locked_entries:\n    cn = canonicalize_name(name)\n    if cn in seen:\n        raise SystemExit(f'duplicate locked entry for {cn}: {seen[cn]} and {link}')\n    seen[cn] = link","typeGuard":null,"tryCatchPattern":"from pip._internal.exceptions import InstallationError\ntry:\n    finder.add_locked_link(project_name, locked_link)\nexcept InstallationError as e:\n    if 'Multiple locked links' in str(e):\n        # resolve the duplicate before retrying\n        ...","preventionTips":["Canonicalize all project names before assembling a lock file.","Run a uniqueness check over canonical names when merging lock files.","Treat duplicate locked entries as a build error in your lock-generation tool."],"tags":["installation","lock-file","duplicate","resolution"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}