{"record":{"id":"ec61c01599931284","repo":"scrapy/scrapy","slug":"type-self-name-doesn-t-support-plain-http","errorCode":null,"errorMessage":"{type(self).__name__} doesn't support plain HTTP.","messagePattern":"(.+?) doesn't support plain HTTP\\.","errorType":"exception","errorClass":"UnsupportedURLSchemeError","httpStatus":null,"severity":"error","filePath":"scrapy/core/downloader/handlers/http2.py","lineNumber":49,"sourceCode":"\nclass H2DownloadHandler(BaseDownloadHandler):\n    lazy = True\n\n    def __init__(self, crawler: Crawler):\n        if not crawler.settings.getbool(\"TWISTED_REACTOR_ENABLED\"):\n            raise NotConfigured(f\"{type(self).__name__} requires a Twisted reactor.\")\n        super().__init__(crawler)\n        self._crawler = crawler\n\n        from twisted.internet import reactor\n\n        self._pool = H2ConnectionPool(reactor, crawler)\n        self._context_factory = _load_context_factory_from_settings(crawler)\n        self._bind_address = crawler.settings.get(\"DOWNLOAD_BIND_ADDRESS\")\n\n    async def download_request(self, request: Request) -> Response:\n        if urlparse_cached(request).scheme == \"http\":  # pragma: no cover\n            raise UnsupportedURLSchemeError(\n                f\"{type(self).__name__} doesn't support plain HTTP.\"\n            )\n        agent = _ScrapyH2Agent(\n            context_factory=self._context_factory,\n            pool=self._pool,\n            bind_address=self._bind_address,\n            crawler=self._crawler,\n        )\n        assert self._crawler.spider\n        with wrap_twisted_exceptions():\n            return await maybe_deferred_to_future(\n                agent.download_request(request, self._crawler.spider)\n            )\n\n    async def close(self) -> None:\n        self._pool.close_connections()\n\n","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/scrapy/scrapy/blob/06af687662112027b4482d31e2714a3cf280a91f/scrapy/core/downloader/handlers/http2.py#L31-L67","documentation":"Raised as UnsupportedURLSchemeError when H2DownloadHandler.download_request receives a plain http:// URL. The handler only implements h2 over TLS; it is meant to be mapped to the https scheme only, and hitting it with http means DOWNLOAD_HANDLERS was configured to route http traffic to it.","triggerScenarios":"DOWNLOAD_HANDLERS['http'] (or a wildcard mapping) pointing at H2DownloadHandler while the spider yields http:// requests; the handler checks urlparse_cached(request).scheme == 'http' and rejects.","commonSituations":"Copying a DOWNLOAD_HANDLERS snippet that maps both http and https to the H2 handler; redirect chains that downgrade https to http while only the https handler was replaced (less common); misreading the handler as a general HTTP/2-for-everything handler.","solutions":["Map only the https scheme to the H2 handler and leave http on the default handler: DOWNLOAD_HANDLERS = {'https': '...http2.H2DownloadHandler'}.","Or use the httpx handler with HTTPX_HTTP2_ENABLED = True, which handles both http and https.","Ensure yielded/redirected URLs use https when the H2 handler owns their scheme."],"exampleFix":"# before\nDOWNLOAD_HANDLERS = {\n    'http': 'scrapy.core.downloader.handlers.http2.H2DownloadHandler',\n    'https': 'scrapy.core.downloader.handlers.http2.H2DownloadHandler',\n}\n\n# after\nDOWNLOAD_HANDLERS = {'https': 'scrapy.core.downloader.handlers.http2.H2DownloadHandler'}","handlingStrategy":"validation","validationCode":"# settings.py — never map http:// to the h2 handler\nassert 'http' not in {\n    k for k, v in DOWNLOAD_HANDLERS.items()\n    if 'handlers.http2' in v\n}, 'H2DownloadHandler only supports https targets'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Map the H2 handler to the https scheme only.","If the site mixes schemes, use the httpx handler for both instead.","Test redirects: an http downgrade from https will cross handler boundaries."],"tags":["http2","http","configuration","downloader","url-scheme"],"backgroundTag":null,"analyzedSha":"06af687662112027b4482d31e2714a3cf280a91f","analyzedAt":"2026-08-15T00:21:48.041Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}