{"record":{"id":"3ff968d055e27951","repo":"RustPython/RustPython","slug":"a-future-is-required-for-destination-argument","errorCode":null,"errorMessage":"A future is required for destination argument","messagePattern":"A future is required for destination argument","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/futures.py","lineNumber":383,"sourceCode":"            dest.set_exception(_convert_future_exc(exception))\n        else:\n            result = source.result()\n            dest.set_result(result)\n\n\ndef _chain_future(source, destination):\n    \"\"\"Chain two futures so that when one completes, so does the other.\n\n    The result (or exception) of source will be copied to destination.\n    If destination is cancelled, source gets cancelled too.\n    Compatible with both asyncio.Future and concurrent.futures.Future.\n    \"\"\"\n    if not isfuture(source) and not isinstance(source,\n                                               concurrent.futures.Future):\n        raise TypeError('A future is required for source argument')\n    if not isfuture(destination) and not isinstance(destination,\n                                                    concurrent.futures.Future):\n        raise TypeError('A future is required for destination argument')\n    source_loop = _get_loop(source) if isfuture(source) else None\n    dest_loop = _get_loop(destination) if isfuture(destination) else None\n\n    def _set_state(future, other):\n        if isfuture(future):\n            _copy_future_state(other, future)\n        else:\n            _set_concurrent_future_state(future, other)\n\n    def _call_check_cancel(destination):\n        if destination.cancelled():\n            if source_loop is None or source_loop is events._get_running_loop():\n                source.cancel()\n            else:\n                source_loop.call_soon_threadsafe(source.cancel)\n\n    def _call_set_state(source):\n        if (destination.cancelled() and","sourceCodeStart":365,"sourceCodeEnd":401,"githubUrl":"https://github.com/RustPython/RustPython/blob/aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd/Lib/asyncio/futures.py#L365-L401","documentation":"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.","triggerScenarios":"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.","commonSituations":"Hand-rolled bridging between asyncio and thread pools; test code passing mocks as destinations; adapting _chain_future examples from outdated answers.","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"],"exampleFix":"# before\nasyncio.futures._chain_future(src_fut, dest_coroutine)  # TypeError\n\n# after\ndest = loop.create_future()\nasyncio.futures._chain_future(src_fut, dest)","handlingStrategy":"type-guard","validationCode":"def make_destination(loop, thread_side=False):\n    import concurrent.futures\n    return concurrent.futures.Future() if thread_side else loop.create_future()","typeGuard":"def is_valid_destination(obj) -> bool:\n    import concurrent.futures\n    return asyncio.isfuture(obj) or isinstance(obj, concurrent.futures.Future)","tryCatchPattern":null,"preventionTips":["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()"],"tags":["asyncio","futures","concurrent-futures","type-error"],"backgroundTag":"asyncio-future-type-mismatch","analyzedSha":"aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd","analyzedAt":"2026-08-17T00:37:52.100Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}