{"record":{"id":"182ebfce04807091","repo":"python/cpython","slug":"future-r-object-does-not-appear-to-be-compatible","errorCode":null,"errorMessage":"{future!r} object does not appear to be compatible with asyncio.Future","messagePattern":"(.+?) object does not appear to be compatible with asyncio\\.Future","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"warning","filePath":"Lib/asyncio/graph.py","lineNumber":46,"sourceCode":"@dataclasses.dataclass(frozen=True, slots=True)\nclass FrameCallGraphEntry:\n    frame: types.FrameType\n\n\n@dataclasses.dataclass(frozen=True, slots=True)\nclass FutureCallGraph:\n    future: futures.Future\n    call_stack: tuple[\"FrameCallGraphEntry\", ...]\n    awaited_by: tuple[\"FutureCallGraph\", ...]\n\n\ndef _build_graph_for_future(\n    future: futures.Future,\n    *,\n    limit: int | None = None,\n) -> FutureCallGraph:\n    if not isinstance(future, futures.Future):\n        raise TypeError(\n            f\"{future!r} object does not appear to be compatible \"\n            f\"with asyncio.Future\"\n        )\n\n    coro = None\n    if get_coro := getattr(future, 'get_coro', None):\n        coro = get_coro() if limit != 0 else None\n\n    st: list[FrameCallGraphEntry] = []\n    awaited_by: list[FutureCallGraph] = []\n\n    while coro is not None:\n        if hasattr(coro, 'cr_await'):\n            # A native coroutine or duck-type compatible iterator\n            st.append(FrameCallGraphEntry(coro.cr_frame))\n            coro = coro.cr_await\n        elif hasattr(coro, 'ag_await'):\n            # A native async generator or duck-type compatible iterator","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/graph.py#L28-L64","documentation":"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).","triggerScenarios":"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.","commonSituations":"Debug tooling or error-reporting libraries that introspect 'never awaited' futures; passing a trio-style nursery object; mocks in tests.","solutions":["Pass only real asyncio.Future/Task instances to capture_call_graph()","Guard with isinstance(x, asyncio.Future) before introspection","For concurrent futures, wrap with asyncio.wrap_future() first"],"exampleFix":"# before\nasyncio.graph.capture_call_graph(future=my_custom_awaitable)  # TypeError\n\n# after\nif isinstance(fut, asyncio.Future):\n    graph = asyncio.graph.capture_call_graph(future=fut)","handlingStrategy":"type-guard","validationCode":"import asyncio\nif not isinstance(fut, asyncio.Future):\n    # cannot introspect; skip graph capture","typeGuard":"def is_asyncio_future(obj) -> bool:\n    return isinstance(obj, asyncio.Future)","tryCatchPattern":null,"preventionTips":["Only pass genuine asyncio.Future/Task to graph introspection","Wrap concurrent futures with wrap_future() first","Use Mock(spec=asyncio.Future) in tests"],"tags":["asyncio","future","debugging","typeerror"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}