RustPython/RustPython · error · TypeError
A future is required for destination argument
Error message
A future is required for destination argument
What it means
The destination-side twin of the source check in _chain_future(): whatever receives the copied state must also be an asyncio.Future or concurrent.futures.Future, otherwise TypeError('A future is required for destination argument'). The destination is usually produced by your own code (loop.create_future() or concurrent.futures.Future()), so this error almost always means a coroutine, awaitable, or unrelated object was passed where a fresh future was expected.
Source
Thrown at Lib/asyncio/futures.py:383
dest.set_exception(_convert_future_exc(exception))
else:
result = source.result()
dest.set_result(result)
def _chain_future(source, destination):
"""Chain two futures so that when one completes, so does the other.
The result (or exception) of source will be copied to destination.
If destination is cancelled, source gets cancelled too.
Compatible with both asyncio.Future and concurrent.futures.Future.
"""
if not isfuture(source) and not isinstance(source,
concurrent.futures.Future):
raise TypeError('A future is required for source argument')
if not isfuture(destination) and not isinstance(destination,
concurrent.futures.Future):
raise TypeError('A future is required for destination argument')
source_loop = _get_loop(source) if isfuture(source) else None
dest_loop = _get_loop(destination) if isfuture(destination) else None
def _set_state(future, other):
if isfuture(future):
_copy_future_state(other, future)
else:
_set_concurrent_future_state(future, other)
def _call_check_cancel(destination):
if destination.cancelled():
if source_loop is None or source_loop is events._get_running_loop():
source.cancel()
else:
source_loop.call_soon_threadsafe(source.cancel)
def _call_set_state(source):
if (destination.cancelled() andView on GitHub (pinned to aaeab4f754)
Solutions
- Create the destination properly: dest = loop.create_future() (asyncio side) or concurrent.futures.Future() (thread side)
- Prefer the public helpers — asyncio.run_coroutine_threadsafe() and wrap_future() — instead of _chain_future
- Validate the destination with asyncio.isfuture()/isinstance checks before chaining
Example fix
# before asyncio.futures._chain_future(src_fut, dest_coroutine) # TypeError # after dest = loop.create_future() asyncio.futures._chain_future(src_fut, dest)
Defensive patterns
Strategy: type-guard
Validate before calling
def make_destination(loop, thread_side=False):
import concurrent.futures
return concurrent.futures.Future() if thread_side else loop.create_future() Type guard
def is_valid_destination(obj) -> bool:
import concurrent.futures
return asyncio.isfuture(obj) or isinstance(obj, concurrent.futures.Future) Prevention
- Create destination futures with loop.create_future() or concurrent.futures.Future()
- Never pass a coroutine or plain awaitable as a chaining destination
- Use run_coroutine_threadsafe()/wrap_future() instead of the private _chain_future()
When it happens
Trigger: Calling the private _chain_future(source, dest) with dest as a coroutine or custom awaitable; passing a Task-like object lacking the Future interface; reusing old snippets that chained into a result container instead of a real future.
Common situations: Hand-rolled bridging between asyncio and thread pools; test code passing mocks as destinations; adapting _chain_future examples from outdated answers.
Related errors
- A future is required for source argument
- {future!r} object does not appear to be compatible with asyn
- cmd must be a string
- loop must be an instance of AbstractEventLoop or None, not '
- policy must be an instance of AbstractEventLoopPolicy or Non
AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17).
Data as JSON: /api/errors/3ff968d055e27951.
Report an issue: GitHub.