JuliusBrussee/caveman · error · TypeError

Expected an HTTPX2 AsyncBaseTransport

Error message

Expected an HTTPX2 AsyncBaseTransport

What it means

CavemanAsyncOpenAITransport is the async counterpart of the OpenAI interception transport and delegates handle_async_request to the supplied transport. It requires an httpx2.AsyncBaseTransport so delegation is guaranteed to support async handling.

Solutions

  1. Pass an httpx2.AsyncBaseTransport, e.g. httpx2.AsyncHTTPTransport()
  2. Swap the sync CavemanOpenAITransport usage for the async class only with async transports
  3. Verify imports point at httpx2, not httpx
  4. isinstance(transport, httpx2.AsyncBaseTransport) check before construction

Example fix

# before
transport = CavemanAsyncOpenAITransport(httpx2.HTTPTransport())  # TypeError: sync transport
# after
transport = CavemanAsyncOpenAITransport(httpx2.AsyncHTTPTransport())
Defensive patterns

Strategy: type-guard

Validate before calling

def ensure_async_transport(transport):
    if not isinstance(transport, httpx2.AsyncBaseTransport):
        raise TypeError("transport must be an httpx2.AsyncBaseTransport")
    return transport

Type guard

def is_async_transport(transport) -> bool:
    return isinstance(transport, httpx2.AsyncBaseTransport)

Try / catch

try:
    transport = CavemanAsyncOpenAITransport(candidate)
except TypeError as e:
    if "AsyncBaseTransport" in str(e):
        candidate = httpx2.AsyncHTTPTransport()
        transport = CavemanAsyncOpenAITransport(candidate)

Prevention

When it happens

Trigger: Constructing CavemanAsyncOpenAITransport with a sync httpx2.BaseTransport (like HTTPTransport), an httpx (v1) async transport, None, or any non-async transport object.

Common situations: Reusing the sync wrapper's transport in the async wrapper after copy-pasting setup code; mixing httpx/httpx2 after migration; passing httpx2.HTTPTransport where AsyncHTTPTransport is required.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/c7d0b602db24638e. Report an issue: GitHub.

Appendix: source

Thrown at packages/middleware/python/caveman_middleware/_httpx2.py:69

        try:
            response = self.transport.handle_request(request)
            observe_response(response, attempt)
            return response
        except BaseException:
            attempt.observe("failed")
            raise
        finally:
            owner.reset(token)

    def close(self):
        self.transport.close()


class CavemanAsyncOpenAITransport(httpx2.AsyncBaseTransport):
    """Async counterpart of CavemanOpenAITransport, using the native pool."""
    def __init__(self, transport):
        if not isinstance(transport, httpx2.AsyncBaseTransport):
            raise TypeError("Expected an HTTPX2 AsyncBaseTransport")
        self.transport = transport

    async def handle_async_request(self, request):
        call = owner.get()
        if not isinstance(call, OpenAICall) or call.transport is not self:
            return await self.transport.handle_async_request(request)
        attempt = call.next_attempt(request)
        attempt.observe("dispatch_intent")
        token = owner.set(attempt)
        try:
            response = await self.transport.handle_async_request(request)
            observe_response(response, attempt)
            return response
        except (asyncio.CancelledError, GeneratorExit):
            attempt.observe("cancelled")
            raise
        except BaseException:
            attempt.observe("failed")

View on GitHub (pinned to 3ee70a1026)