PrefectHQ/fastmcp · error · RuntimeError

Unexpected ASGI message type: {message['type']}

Error message

Unexpected ASGI message type: {message['type']}

What it means

During ASGI response streaming, the transport's send_response handler accepts only 'http.response.start' and 'http.response.body' messages. Any other ASGI message type (e.g. lifecycle or websocket messages on an HTTP response path) triggers this RuntimeError.

Source

Thrown at fastmcp_slim/fastmcp/utilities/asgi_transport.py:181

                request_delivered = True
                return {
                    "type": "http.request",
                    "body": request_body,
                    "more_body": False,
                }
            await client_disconnected.wait()
            return {"type": "http.disconnect"}

        async def send_response(message: Message) -> None:
            nonlocal response_status, response_headers, start_received
            if message["type"] == "http.response.start":
                start_received = True
                response_status = message["status"]
                response_headers = list(message.get("headers", []))
                response_started.set()
                return
            if message["type"] != "http.response.body":
                raise RuntimeError(f"Unexpected ASGI message type: {message['type']}")
            body: bytes = message.get("body", b"")
            if body:
                await chunk_writer.send(body)
            if not message.get("more_body", False):
                await chunk_writer.aclose()

        async def run_application() -> None:
            nonlocal application_error
            try:
                await self._app(scope, receive_request, send_response)
            except Exception as exc:
                # The bridge is the application's outermost boundary: a crash must fail the
                # originating request (or show up in the already-started response), never
                # tear down the task group shared with every other in-flight request.
                application_error = exc
            finally:
                response_started.set()
                await chunk_writer.aclose()

View on GitHub (pinned to 1f02114297)

Solutions

  1. Inspect the ASGI app/middleware for messages emitted outside the HTTP response contract
  2. Ensure the request scope is a plain HTTP request when using this transport
  3. Log the offending message['type'] to identify which component misbehaves
Defensive patterns

Strategy: try-catch

Validate before calling

# Ensure scope type is http before sending requests through the transport
assert scope["type"] == "http"

Try / catch

try:
    response = await client.send(request)
except RuntimeError as e:
    if "Unexpected ASGI message type" in str(e):
        logger.error("ASGI app emitted non-HTTP message: %s", e)
        # inspect middleware / app message emission
    else:
        raise

Prevention

When it happens

Trigger: The ASGI app sends a message type other than http.response.start/body while the transport is reading the HTTP response, such as 'http.disconnect' misuse or websocket-scope messages.

Common situations: ASGI apps with buggy custom middleware sending non-HTTP messages; using the transport against a websocket or lifespan scope; framework upgrades changing message emission.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/3d9f9b1f2ca96070. Report an issue: GitHub.