{"record":{"id":"e874ee44c15f5dc5","repo":"python/cpython","slug":"a-coroutine-was-expected-got-coro-r","errorCode":null,"errorMessage":"a coroutine was expected, got {coro!r}","messagePattern":"a coroutine was expected, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/tasks.py","lineNumber":93,"sourceCode":"    #   as it schedules __wakeup() to be called (which calls __step() so\n    #   we way that __step() is scheduled).\n    # * It transitions from 2 to 3 when __step() is executed, and it clears\n    #   _fut_waiter to None.\n\n    # If False, don't log a message if the task is destroyed while its\n    # status is still pending\n    _log_destroy_pending = True\n\n    def __init__(self, coro, *, loop=None, name=None, context=None,\n                 eager_start=False):\n        super().__init__(loop=loop)\n        if self._source_traceback:\n            del self._source_traceback[-1]\n        if not coroutines.iscoroutine(coro):\n            # raise after Future.__init__(), attrs are required for __del__\n            # prevent logging for pending task in __del__\n            self._log_destroy_pending = False\n            raise TypeError(f\"a coroutine was expected, got {coro!r}\")\n\n        if name is None:\n            self._name = f'Task-{_task_name_counter()}'\n        else:\n            self._name = str(name)\n\n        self._num_cancels_requested = 0\n        self._must_cancel = False\n        self._fut_waiter = None\n        self._coro = coro\n        if context is None:\n            self._context = contextvars.copy_context()\n        else:\n            self._context = context\n\n        if eager_start and self._loop.is_running():\n            self.__eager_start()\n        else:","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/tasks.py#L75-L111","documentation":"TypeError raised by Task.__init__ when the first argument is not a coroutine object (checked with coroutines.iscoroutine). Tasks wrap exactly one coroutine; passing anything else — an async function itself, a plain function, a generator, a Future — is rejected immediately (with pending-coroutine logging disabled since nothing valid exists to destroy).","triggerScenarios":"asyncio.Task(my_async_func) instead of asyncio.Task(my_async_func()); same for loop.create_task(async_func); passing a coroutine function reference stored in a variable; passing a functools.partial of an async function without calling it; on non-default loops, types registered with a different event loop policy may also fail iscoroutine.","commonSituations":"Forgetting the parentheses — the most common form; passing a callback registry value that is a function not a coroutine object; mixing awaitable objects (Futures, objects with __await__) that are not coroutines and must go through ensure_future; refactors from callbacks to async that left a call operator behind.","solutions":["Call the function: create the coroutine object first — coro = my_async(); then Task(coro) / asyncio.create_task(my_async())","For generic awaitables (Futures, custom __await__), use asyncio.ensure_future() which wraps appropriately","Double-check higher-order APIs: registries and dispatch maps should store functions but invoke them as value() when spawning"],"exampleFix":"// before\ntask = asyncio.create_task(poll_service)      # function, not coroutine\n\n// after\ntask = asyncio.create_task(poll_service())","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"import inspect\n\ndef spawn(loop, awaitable):\n    if inspect.iscoroutinefunction(awaitable):\n        raise TypeError('forgot to call: pass the coroutine object, not the function')\n    if not inspect.iscoroutine(awaitable):\n        return asyncio.ensure_future(awaitable)\n    return loop.create_task(awaitable)","tryCatchPattern":"null","preventionTips":["Always write the call: create_task(my_func())","Use ensure_future for generic awaitables, Task/create_task only for coroutine objects","Lint for create_task identifiers not followed by '(' inside its argument"],"tags":["asyncio","tasks","type-error","api-misuse"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}