{"id":"f21cd9bf2b1f56c0","repo":"aio-libs/aiohttp","slug":"scheme-not-supported","errorCode":null,"errorMessage":"Scheme not supported","messagePattern":"Scheme not supported","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_urldispatcher.py","lineNumber":786,"sourceCode":"class Domain(AbstractRuleMatching):\n    re_part = re.compile(r\"(?!-)[a-z\\d-]{1,63}(?<!-)\")\n\n    def __init__(self, domain: str) -> None:\n        super().__init__()\n        self._domain = self.validation(domain)\n\n    @property\n    def canonical(self) -> str:\n        return self._domain\n\n    def validation(self, domain: str) -> str:\n        if not isinstance(domain, str):\n            raise TypeError(\"Domain must be str\")\n        domain = domain.rstrip(\".\").lower()\n        if not domain:\n            raise ValueError(\"Domain cannot be empty\")\n        elif \"://\" in domain:\n            raise ValueError(\"Scheme not supported\")\n        url = URL(\"http://\" + domain)\n        assert url.raw_host is not None\n        if not all(self.re_part.fullmatch(x) for x in url.raw_host.split(\".\")):\n            raise ValueError(\"Domain not valid\")\n        if url.port == 80:\n            return url.raw_host\n        return f\"{url.raw_host}:{url.port}\"\n\n    async def match(self, request: Request) -> bool:\n        host = request.headers.get(hdrs.HOST)\n        if not host:\n            return False\n        return self.match_domain(host)\n\n    def match_domain(self, host: str) -> bool:\n        return host.lower() == self._domain\n\n    def get_info(self) -> _InfoDict:","sourceCodeStart":768,"sourceCodeEnd":804,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/web_urldispatcher.py#L768-L804","documentation":"Raised as ValueError by Domain.validation when the domain string contains '://' — indicating a scheme (e.g. 'https://example.com') was passed where only a bare host is expected. Domain matches on the Host header, which never includes a scheme, so a schemed input is rejected.","triggerScenarios":"Constructing aiohttp.web.Domain('https://example.com'), Domain('http://api.example.com:8080'), or app.add_domain('https://example.com', sub_app). Passing a full URL instead of just the host.","commonSituations":"Copy-pasting a full URL from a browser/address bar into domain config; reading base URLs from config and passing them whole; confusing add_domain (host-based) with prefix-based sub-app mounting.","solutions":["Pass only the host (optionally with port): Domain('example.com') or Domain('example.com:8080').","Strip the scheme before constructing: extract host via yarl: URL(url).raw_host.","If you meant path-based mounting, use app.add_sub_app(prefix, sub_app) instead of add_domain."],"exampleFix":"# before\napp.add_domain('https://api.example.com', sub_app)\n\n# after\nfrom yarl import URL\nhost = URL('https://api.example.com').raw_host\napp.add_domain(host, sub_app)","handlingStrategy":"validation","validationCode":"from yarl import URL\n\ndef host_from_url(value: str) -> str:\n    if '://' in value:\n        u = URL(value)\n        host = u.raw_host\n        if u.port and u.port != 80:\n            host = f'{host}:{u.port}'\n        return host\n    return value","typeGuard":"def is_bare_host(domain) -> bool:\n    return isinstance(domain, str) and '://' not in domain and bool(domain.strip())","tryCatchPattern":"try:\n    app.add_domain(host, sub_app)\nexcept ValueError as e:\n    if 'Scheme not supported' in str(e):\n        from yarl import URL\n        app.add_domain(URL(host).raw_host, sub_app)\n    else:\n        raise","preventionTips":["Pass bare hosts to add_domain, never full URLs.","Normalize config base URLs to hosts with yarl before building Domain rules.","Distinguish host-based (add_domain) from path-based (add_sub_app) mounting."],"tags":["aiohttp","domain-matching","value-error","url","configuration"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}