{"record":{"id":"8a5ee3b8237951d4","repo":"pika/pika","slug":"on-done-arg-must-be-callable-but-got-on-done-r","errorCode":null,"errorMessage":"on_done arg must be callable, but got {on_done!r}","messagePattern":"on_done arg must be callable, but got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pika/adapters/asyncio_connection.py","lineNumber":259,"sourceCode":"        :param fd: File descriptor\n        \"\"\"\n        LOGGER.debug('remove_writer(%s)', fd)\n        return self._loop.remove_writer(fd)\n\n    def _schedule_and_wrap_in_io_ref(\n        self, coro: Awaitable[Any],\n        on_done: Callable[[base_connection.BaseConnection | BaseException],\n                          None]\n    ) -> _AsyncioIOReference:\n        \"\"\"\n        Schedule the coroutine to run and return _AsyncioIOReference.\n\n        :param coro: Coroutine to schedule.\n        :param on_done: User callback that takes the completion result or exception as its only arg.\n            It will not be called if the operation was cancelled.\n        \"\"\"\n        if not callable(on_done):\n            raise TypeError(\n                f'on_done arg must be callable, but got {on_done!r}')\n\n        return _AsyncioIOReference(asyncio.ensure_future(coro, loop=self._loop),\n                                   on_done)\n\n\nclass _TimerHandle(nbio_interface.AbstractTimerReference):\n    \"\"\"This module's adaptation of `nbio_interface.AbstractTimerReference`.\"\"\"\n\n    def __init__(self, handle: asyncio.Handle) -> None:\n        \"\"\"\n\n        :param handle:\n        \"\"\"\n        self._handle: asyncio.Handle | None = handle\n\n    @override\n    def cancel(self) -> None:","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/pika/pika/blob/34a407b24f08f2307578ceff870b6d7a12e7fdca/pika/adapters/asyncio_connection.py#L241-L277","documentation":"`_AsyncioIOServicesAdapter._schedule_and_wrap_in_io_ref` wraps an asyncio future/coroutine and registers an `on_done` callback for completion. The guard rejects a non-callable `on_done` immediately so the future is never left without a completion handler. This method is reached through the public `getaddrinfo` method (which takes `on_done`) and through streaming-connection setup.","triggerScenarios":"Calling `nbio.getaddrinfo(host, port, on_done=<non-callable>)` on the asyncio nbio adapter, or subclassing `_AsyncioIOServicesAdapter` / implementing a custom transport that forwards a None or non-callable completion callback into this method.","commonSituations":"Implementing a custom `AbstractStreamTransport` or `AbstractFileDescriptorIOServices` and forgetting to pass the completion callback, or passing a string attribute name or a result object instead of a function for `on_done`.","solutions":["Pass a real callable (function/lambda/bound method) as `on_done`.","If you don't need completion notification, pass a no-op: `on_done=lambda *_: None`."],"exampleFix":"# before\nnbio.getaddrinfo(host, port, on_done=None)\n# after\nnbio.getaddrinfo(host, port, on_done=lambda addrinfo_or_exc: None)","handlingStrategy":"type-guard","validationCode":"if not callable(on_done):\n    raise TypeError('on_done must be callable')\nnbio.getaddrinfo(host, port, on_done=on_done)","typeGuard":"def is_callable_zero_arg(fn) -> bool:\n    return callable(fn)","tryCatchPattern":null,"preventionTips":["Pass lambdas or bound methods for completion callbacks.","Use a no-op (lambda *_: None) when you don't need the result.","Avoid extending _AsyncioIOServicesAdapter unless necessary."],"tags":["asyncio","callback","validation","internal"],"backgroundTag":null,"analyzedSha":"34a407b24f08f2307578ceff870b6d7a12e7fdca","analyzedAt":"2026-08-07T23:58:35.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}