{"record":{"id":"2f6d35d88ef5fb38","repo":"pypa/pip","slug":"package-url-url-r-cannot-contain-fragments-in-co","errorCode":null,"errorMessage":"Package URL {url!r} cannot contain fragments in combination with subdirectory field (in {pylock_path_or_url!r})","messagePattern":"Package URL (.+?) cannot contain fragments in combination with subdirectory field \\(in (.+?)\\)","errorType":"exception","errorClass":"InstallationError","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/utils/pylock.py","lineNumber":196,"sourceCode":"            if _is_url(pylock_path_or_url):\n                raise InstallationError(\n                    f\"Absolute paths are not supported in pylock files obtained \"\n                    f\"from a URL: {path!r} in {pylock_path_or_url!r}\"\n                )\n            return path_to_url(path)\n    else:\n        assert url is not None  # guaranteed by packaging.pylock validation\n        return url\n\n\ndef package_vcs_requirement_url(\n    pylock_path_or_url: str, package_vcs: PackageVcs\n) -> str:\n    dist_url = _package_dist_url(pylock_path_or_url, package_vcs.path, package_vcs.url)\n    url = f\"{package_vcs.type}+{dist_url}@{package_vcs.commit_id}\"\n    if package_vcs.subdirectory:\n        if \"#\" in url:\n            raise InstallationError(\n                f\"Package URL {url!r} cannot contain fragments in combination \"\n                f\"with subdirectory field (in {pylock_path_or_url!r})\"\n            )\n        url += \"#subdirectory=\" + package_vcs.subdirectory\n    return url\n\n\ndef package_archive_requirement_url(\n    pylock_path_or_url: str, package_archive: PackageArchive\n) -> str:\n    url = _package_dist_url(\n        pylock_path_or_url, package_archive.path, package_archive.url\n    )\n    if package_archive.subdirectory:\n        if \"#\" in url:\n            raise InstallationError(\n                f\"Package URL {url!r} cannot contain fragments in combination \"\n                f\"with subdirectory field (in {pylock_path_or_url!r})\"","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_internal/utils/pylock.py#L178-L214","documentation":"Raised as InstallationError by package_vcs_requirement_url (pylock.py:196) when a VCS package entry in a pylock file already has a # fragment in its constructed URL and also specifies a subdirectory field. URL fragments are used for subdirectory selection, so pip appends #subdirectory=<value> to the VCS URL; if the URL already contains a # (e.g. from a ref or existing fragment), the resulting URL would be ambiguous or malformed. pip refuses rather than produce a broken URL.","triggerScenarios":"A pylock VCS package whose dist_url (computed from path/url) already contains a '#', and package_vcs.subdirectory is non-empty. The check at line 195 `if '#' in url` triggers the raise at 196.","commonSituations":"A VCS URL like git+https://repo.git@branch#egg=pkg combined with a subdirectory field in the same lock entry. A pylock file generated by a tool that didn't strip conflicting fragments. Manually editing a lock file and adding both a fragment and a subdirectory.","solutions":["Remove the # fragment from the VCS URL in the lock file and rely solely on the subdirectory field.","If the fragment encodes a ref/branch, move it into the @revision portion of the VCS URL instead of as a # fragment.","Remove the subdirectory field if the fragment is the intended mechanism for subdirectory selection.","Regenerate the pylock file with `pip lock` so VCS URLs and subdirectory fields are consistent."],"exampleFix":"// before\nurl = \"git+https://repo.git@main#egg=pkg\"\nsubdirectory = \"subdir\"\n\n// after\nurl = \"git+https://repo.git@main\"\nsubdirectory = \"subdir\"","handlingStrategy":"validation","validationCode":"def validate_vcs_url_with_subdir(url: str, subdirectory: str | None) -> bool:\n    \"\"\"True if a VCS URL + subdirectory combination is safe (no conflicting fragment).\"\"\"\n    if subdirectory and '#' in url:\n        return False  # fragment + subdirectory conflict\n    return True","typeGuard":"def has_fragment_subdir_conflict(url: str, subdirectory: str | None) -> bool:\n    \"\"\"True if the URL has a # fragment AND subdirectory is set (conflict).\"\"\"\n    return bool(subdirectory) and '#' in url","tryCatchPattern":null,"preventionTips":["Keep VCS ref/branch in the @revision part of the URL, not as a # fragment.","Use the subdirectory field exclusively for subdir selection — never combine with URL fragments.","Validate lock files with a schema checker before installing."],"tags":["pylock","vcs","url-fragment","subdirectory","validation"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}