python/cpython · warning · TypeError

{future!r} object does not appear to be compatible with asyn

Error message

{future!r} object does not appear to be compatible with asyncio.Future

What it means

The internal graph builder used by asyncio's future debugging (e.g. when a future is garbage-collected while never-awaited warnings are emitted) requires an exact asyncio.Future. A Task-like or duck-typed object lacking the Future interface raises this TypeError because call-graph introspection depends on Future internals (get_coro, _asyncio_awaited_by).

Source

Thrown at Lib/asyncio/graph.py:46

@dataclasses.dataclass(frozen=True, slots=True)
class FrameCallGraphEntry:
    frame: types.FrameType


@dataclasses.dataclass(frozen=True, slots=True)
class FutureCallGraph:
    future: futures.Future
    call_stack: tuple["FrameCallGraphEntry", ...]
    awaited_by: tuple["FutureCallGraph", ...]


def _build_graph_for_future(
    future: futures.Future,
    *,
    limit: int | None = None,
) -> FutureCallGraph:
    if not isinstance(future, futures.Future):
        raise TypeError(
            f"{future!r} object does not appear to be compatible "
            f"with asyncio.Future"
        )

    coro = None
    if get_coro := getattr(future, 'get_coro', None):
        coro = get_coro() if limit != 0 else None

    st: list[FrameCallGraphEntry] = []
    awaited_by: list[FutureCallGraph] = []

    while coro is not None:
        if hasattr(coro, 'cr_await'):
            # A native coroutine or duck-type compatible iterator
            st.append(FrameCallGraphEntry(coro.cr_frame))
            coro = coro.cr_await
        elif hasattr(coro, 'ag_await'):
            # A native async generator or duck-type compatible iterator

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Pass only real asyncio.Future/Task instances to capture_call_graph()
  2. Guard with isinstance(x, asyncio.Future) before introspection
  3. For concurrent futures, wrap with asyncio.wrap_future() first

Example fix

# before
asyncio.graph.capture_call_graph(future=my_custom_awaitable)  # TypeError

# after
if isinstance(fut, asyncio.Future):
    graph = asyncio.graph.capture_call_graph(future=fut)
Defensive patterns

Strategy: type-guard

Validate before calling

import asyncio
if not isinstance(fut, asyncio.Future):
    # cannot introspect; skip graph capture

Type guard

def is_asyncio_future(obj) -> bool:
    return isinstance(obj, asyncio.Future)

Prevention

When it happens

Trigger: Calling asyncio.graph._build_graph_for_future (or capture_call_graph with an explicit future) with a custom awaitable, a concurrent.futures.Future, or a third-party task implementation.

Common situations: Debug tooling or error-reporting libraries that introspect 'never awaited' futures; passing a trio-style nursery object; mocks in tests.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/182ebfce04807091. Report an issue: GitHub.