python/cpython · error · RuntimeError

Task does not support set_exception operation

Error message

Task does not support set_exception operation

What it means

RuntimeError raised by Task.set_exception(): like set_result, it is permanently disabled on Task because a task's outcome comes only from running its coroutine. The method exists only because Task subclasses Future; invoking it is always a programming error.

Source

Thrown at Lib/asyncio/tasks.py:147

        return base_tasks._task_repr(self)

    def get_coro(self):
        return self._coro

    def get_context(self):
        return self._context

    def get_name(self):
        return self._name

    def set_name(self, value):
        self._name = str(value)

    def set_result(self, result):
        raise RuntimeError('Task does not support set_result operation')

    def set_exception(self, exception):
        raise RuntimeError('Task does not support set_exception operation')

    def get_stack(self, *, limit=None):
        """Return the list of stack frames for this task's coroutine.

        If the coroutine is not done, this returns the stack where it is
        suspended.  If the coroutine has completed successfully or was
        cancelled, this returns an empty list.  If the coroutine was
        terminated by an exception, this returns the list of traceback
        frames.

        The frames are always ordered from oldest to newest.

        The optional limit gives the maximum number of frames to
        return; by default all available frames are returned.  Its
        meaning differs depending on whether a stack or a traceback is
        returned: the newest frames of a stack are returned, but the
        oldest frames of a traceback are returned.  (This matches the
        behavior of the traceback module.)

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Fail a loop.create_future() instead; the awaiting task should observe and re-raise it
  2. Deliver errors to running tasks through cancellation (task.cancel()) or via a queue/future the task awaits
  3. Type-check helper inputs: if futures.isfuture(x) and not isinstance(x, asyncio.Task) before calling set_exception

Example fix

// before
def abort_waiter(fut, err):
    loop.call_soon_threadsafe(fut.set_exception, err)  # crashes if fut is a Task

// after
waiter = loop.create_future()  # created where completion is controlled
async def consumer():
    try:
        return await waiter
    except MyAbort:
        return None
Defensive patterns

Strategy: validation

Validate before calling

null

Type guard

import asyncio

def is_failable_future(f) -> bool:
    return isinstance(f, asyncio.Future) and not isinstance(f, asyncio.Task)

Try / catch

null

Prevention

When it happens

Trigger: Calling task.set_exception(exc) directly; passing a Task where a manually-completed Future is expected in error-injection code, test doubles, or bridges that 'fail' a future (e.g. call_soon_threadsafe(fut.set_exception, err)) and receiving a Task.

Common situations: Error-injection test helpers built around Future APIs; thread-to-loop bridges that fail a pending wait on shutdown; shared 'waiter' abstractions that accept both tasks and futures via ensure_future and then try to fail them externally.

Related errors


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