{"record":{"id":"4d311eaea84db0aa","repo":"python/cpython","slug":"task-does-not-support-set-result-operation","errorCode":null,"errorMessage":"Task does not support set_result operation","messagePattern":"Task does not support set_result operation","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/tasks.py","lineNumber":144,"sourceCode":"    __class_getitem__ = classmethod(GenericAlias)\n\n    def __repr__(self):\n        return base_tasks._task_repr(self)\n\n    def get_coro(self):\n        return self._coro\n\n    def get_context(self):\n        return self._context\n\n    def get_name(self):\n        return self._name\n\n    def set_name(self, value):\n        self._name = str(value)\n\n    def set_result(self, result):\n        raise RuntimeError('Task does not support set_result operation')\n\n    def set_exception(self, exception):\n        raise RuntimeError('Task does not support set_exception operation')\n\n    def get_stack(self, *, limit=None):\n        \"\"\"Return the list of stack frames for this task's coroutine.\n\n        If the coroutine is not done, this returns the stack where it is\n        suspended.  If the coroutine has completed successfully or was\n        cancelled, this returns an empty list.  If the coroutine was\n        terminated by an exception, this returns the list of traceback\n        frames.\n\n        The frames are always ordered from oldest to newest.\n\n        The optional limit gives the maximum number of frames to\n        return; by default all available frames are returned.  Its\n        meaning differs depending on whether a stack or a traceback is","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/tasks.py#L126-L162","documentation":"RuntimeError raised by Task.set_result(): Task inherits from Future but its result is determined solely by driving the wrapped coroutine, so manually resolving it is forbidden. Any generic 'complete this future' code path that receives a Task hits this immediately.","triggerScenarios":"Calling task.set_result(value) directly; a helper written against futures (e.g. a waiter registry, timeout helper, or thread-bridge using loop.call_soon_threadsafe(fut.set_result, x)) that was handed a Task instead of a plain Future.","commonSituations":"Waiter maps that store whatever create_future/ensure_future returned; mixing Task and Future in the same synchronization structure; adapting threading code where 'set the result' is the normal completion idiom; wake-up signals between a protocol and its consumer implemented with futures.","solutions":["Use loop.create_future() for manually completed synchronization primitives; keep Tasks only for scheduled coroutines","Change generic completion helpers to call loop.call_soon_threadsafe(fut.set_result, ...) on a Future they created themselves","If you need to deliver a value to a Task, feed it via a queue, event, or future the task awaits"],"exampleFix":"// before\nwakeup = asyncio.create_task(wait_and_process())\nloop.call_soon_threadsafe(wakeup.set_result, data)  # RuntimeError\n\n// after\nwakeup = loop.create_future()\nloop.call_soon_threadsafe(wakeup.set_result, data)\ndata = await wakeup  # consumed by the coroutine that needs it","handlingStrategy":"validation","validationCode":"null","typeGuard":"import asyncio\n\ndef is_completable_future(f) -> bool:\n    return isinstance(f, asyncio.Future) and not isinstance(f, asyncio.Task)","tryCatchPattern":"null","preventionTips":["Create manual-completion waiters with loop.create_future(), never create_task","Bridges that set results must own the future they complete","Deliver values to tasks via queues/events the task awaits"],"tags":["asyncio","tasks","futures","api-misuse"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}