{"id":"1a226a5f44785e5c","repo":"pypa/pip","slug":"the-url-url-r-has-an-empty-revision-after-wh","errorCode":null,"errorMessage":"The URL {url!r} has an empty revision (after @) which is not supported. Include a revision after @ or remove @ from the URL.","messagePattern":"The URL (.+?) has an empty revision \\(after @\\) which is not supported\\. Include a revision after @ or remove @ from the URL\\.","errorType":"exception","errorClass":"InstallationError","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/vcs/versioncontrol.py","lineNumber":395,"sourceCode":"        and auth info to use.\n\n        Returns: (url, rev, (username, password)).\n        \"\"\"\n        scheme, netloc, path, query, frag = urllib.parse.urlsplit(url)\n        if \"+\" not in scheme:\n            raise ValueError(\n                f\"Sorry, {url!r} is a malformed VCS url. \"\n                \"The format is <vcs>+<protocol>://<url>, \"\n                \"e.g. svn+http://myrepo/svn/MyApp#egg=MyApp\"\n            )\n        # Remove the vcs prefix.\n        scheme = scheme.split(\"+\", 1)[1]\n        netloc, user_pass = cls.get_netloc_and_auth(netloc, scheme)\n        rev = None\n        if \"@\" in path:\n            path, rev = path.rsplit(\"@\", 1)\n            if not rev:\n                raise InstallationError(\n                    f\"The URL {url!r} has an empty revision (after @) \"\n                    \"which is not supported. Include a revision after @ \"\n                    \"or remove @ from the URL.\"\n                )\n            rev = urllib.parse.unquote(rev)\n        url = urllib.parse.urlunsplit((scheme, netloc, path, query, \"\"))\n        return url, rev, user_pass\n\n    @staticmethod\n    def make_rev_args(username: str | None, password: HiddenText | None) -> CommandArgs:\n        \"\"\"\n        Return the RevOptions \"extra arguments\" to use in obtain().\n        \"\"\"\n        return []\n\n    def get_url_rev_options(self, url: HiddenText) -> tuple[HiddenText, RevOptions]:\n        \"\"\"\n        Return the URL and RevOptions object to use in obtain(),","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_internal/vcs/versioncontrol.py#L377-L413","documentation":"Raised by `get_url_rev_and_auth` when a VCS URL contains an `@` separator in the path (the revision delimiter) but the segment after the final `@` is empty. pip interprets `<url>@<rev>` to pin a specific revision; an empty rev (`...@` or `...@#egg=...`) is ambiguous and unsupported, so it aborts with an InstallationError rather than silently installing HEAD.","triggerScenarios":"Pip parses a VCS URL where `'@' in path` is True, then `path.rsplit('@', 1)` yields an empty rev string. Happens for URLs like `git+https://host/repo.git@` or `svn+https://host/repo/@#egg=Pkg` where nothing follows the `@` before the fragment/query.","commonSituations":"Typos in `requirements.txt`; copy-pasting a URL and truncating the revision; templating scripts that substitute an empty commit/tag variable after `@`; CI configs where a branch/tag env var is unset.","solutions":["Append a concrete revision after `@`, e.g. `git+https://host/repo.git@v1.2.3`.","If you want the default/HEAD revision, remove the trailing `@` entirely.","Check that any variable substituted after `@` (tag, commit SHA, branch) is non-empty in your CI/requirements template."],"exampleFix":"# before\npip install git+https://github.com/org/repo.git@\n\n# after\npip install git+https://github.com/org/repo.git@v1.2.3\n# or, for HEAD:\npip install git+https://github.com/org/repo.git","handlingStrategy":"validation","validationCode":"import urllib.parse\n\ndef validate_vcs_rev(url: str) -> None:\n    path = urllib.parse.urlsplit(url).path\n    if \"@\" in path:\n        rev = path.rsplit(\"@\", 1)[1]\n        if not rev:\n            raise ValueError(f\"Empty revision after @ in {url!r}\")","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Either omit `@` entirely (for HEAD) or always specify a non-empty rev.","In CI templates, fail fast if the rev variable is empty before substitution.","Lint `requirements.txt` for trailing `@` characters."],"tags":["vcs","url-parsing","requirements","configuration"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}