{"id":"a0ca0899d18106b6","repo":"encode/httpx","slug":"cannot-use-an-async-handler-in-a-sync-client","errorCode":null,"errorMessage":"Cannot use an async handler in a sync Client","messagePattern":"Cannot use an async handler in a sync Client","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"httpx/_transports/mock.py","lineNumber":26,"sourceCode":"SyncHandler = typing.Callable[[Request], Response]\nAsyncHandler = typing.Callable[[Request], typing.Coroutine[None, None, Response]]\n\n\n__all__ = [\"MockTransport\"]\n\n\nclass MockTransport(AsyncBaseTransport, BaseTransport):\n    def __init__(self, handler: SyncHandler | AsyncHandler) -> None:\n        self.handler = handler\n\n    def handle_request(\n        self,\n        request: Request,\n    ) -> Response:\n        request.read()\n        response = self.handler(request)\n        if not isinstance(response, Response):  # pragma: no cover\n            raise TypeError(\"Cannot use an async handler in a sync Client\")\n        return response\n\n    async def handle_async_request(\n        self,\n        request: Request,\n    ) -> Response:\n        await request.aread()\n        response = self.handler(request)\n\n        # Allow handler to *optionally* be an `async` function.\n        # If it is, then the `response` variable need to be awaited to actually\n        # return the result.\n\n        if not isinstance(response, Response):\n            response = await response\n\n        return response\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_transports/mock.py#L8-L44","documentation":"Raised by MockTransport.handle_request (the synchronous path) when the handler callable returns a coroutine instead of a Response. MockTransport accepts either a sync or async handler, but the sync handle_request cannot await a coroutine, so it detects the non-Response return and raises TypeError. It indicates a mismatch between the Client type (sync) and the handler (async).","triggerScenarios":"Passing an 'async def handler(request)' to httpx.MockTransport and then using it from a sync httpx.Client (client.get(...)). The sync code path calls handle_request, which calls the handler synchronously and gets back a coroutine object.","commonSituations":"Writing tests that share one MockTransport between sync and async code; refactoring a sync test to async but forgetting to switch Client to AsyncClient; copy-pasting an async handler example into a sync test suite.","solutions":["Use httpx.AsyncClient with the MockTransport when your handler is 'async def'.","Or rewrite the handler as a plain 'def' returning httpx.Response when using a sync Client.","Keep one MockTransport per Client flavour; do not share between sync and async tests.","Add a unit-level check: if asyncio.iscoroutinefunction(handler) and sync client -> fail fast in test setup."],"exampleFix":"// before\ndef handler(request):  # actually defined as 'async def' elsewhere\n    return httpx.Response(200)\ntransport = httpx.MockTransport(handler)\nclient = httpx.Client(transport=transport)  # TypeError at request time\n\n// after\nasync def handler(request):\n    return httpx.Response(200)\ntransport = httpx.MockTransport(handler)\nclient = httpx.AsyncClient(transport=transport)","handlingStrategy":"type-guard","validationCode":"import asyncio, typing\nimport httpx\n\ndef make_mock_transport(handler):\n    is_async = asyncio.iscoroutinefunction(handler)\n    transport = httpx.MockTransport(handler)\n    return transport, is_async\n\ntransport, is_async = make_mock_transport(my_handler)\nclient = (\n    httpx.AsyncClient(transport=transport) if is_async\n    else httpx.Client(transport=transport)\n)","typeGuard":"import asyncio, typing\n\ndef is_async_handler(handler: typing.Callable) -> bool:\n    return asyncio.iscoroutinefunction(handler)","tryCatchPattern":"try:\n    response = client.get(\"https://test.local/\")\nexcept TypeError as e:\n    if \"async handler\" in str(e):\n        raise TypeError(\"Use httpx.AsyncClient for async MockTransport handlers\") from e\n    raise","preventionTips":["Decide upfront whether a test is sync or async; align Client and handler.","Do not share one MockTransport across sync and async clients.","Add a pytest fixture that pairs the right Client class with the handler flavour."],"tags":["mock","testing","async","sync","type-mismatch"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}