{"record":{"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/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_internal/vcs/versioncontrol.py#L377-L413","documentation":"Raised by VersionControl.get_url_rev_and_auth() when the URL path contains an '@' separator but the revision string after it is empty. The '@' syntax specifies a VCS revision/commit; an empty revision is ambiguous and unsupported.","triggerScenarios":"Calling get_url_rev_and_auth(url) where path.rsplit('@', 1) yields an empty rev string. For example, 'git+https://example.com/repo.git@' — the '@' is present but nothing follows it.","commonSituations":"A typo leaving a trailing '@' in the URL. A requirements file with a URL like 'git+https://.../@' from a botched variable substitution. Copying a URL that had a revision deleted but the '@' left behind.","solutions":["Remove the trailing '@' from the URL, or add a valid revision after it","Specify a concrete revision: branch, tag, or commit hash after the '@'","Validate requirement URLs in your requirements.txt for stray '@' characters"],"exampleFix":"// before\npip install \"git+https://github.com/user/repo.git@\"\n// after\n# either remove the @\npip install git+https://github.com/user/repo.git\n# or specify a revision\npip install \"git+https://github.com/user/repo.git@v1.2.3\"","handlingStrategy":"validation","validationCode":"import urllib.parse\n\ndef vcs_url_has_valid_revision(url: str) -> bool:\n    path = urllib.parse.urlsplit(url).path\n    if '@' not in path:\n        return True\n    _, _, rev = path.rpartition('@')\n    return bool(rev)\n\n# before installing\nif not vcs_url_has_valid_revision(url):\n    raise ValueError(f'URL has empty revision after @: {url}')","typeGuard":"def revision_is_nonempty(url_path: str) -> bool:\n    if '@' not in url_path:\n        return True\n    return bool(url_path.rsplit('@', 1)[-1])","tryCatchPattern":"from pip._internal.exceptions import InstallationError\n\ntry:\n    url, rev, auth = vc.get_url_rev_and_auth(url)\nexcept InstallationError as e:\n    if 'empty revision' in str(e):\n        raise ConfigError(f'remove trailing @ or add a revision: {e}')\n    raise","preventionTips":["Avoid trailing '@' in VCS requirement URLs","Specify concrete revisions (tags, commits, branches) after '@'","Lint requirements files for stray '@' characters","Use '#egg=' for the project name, not '@'"],"tags":["vcs","url","revision","requirements","configuration"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}