{"record":{"id":"6674f70e22025db6","repo":"pika/pika","slug":"unexpected-callback-for-asynchronous-nowait-oper","errorCode":null,"errorMessage":"Unexpected callback for asynchronous (nowait) operation.","messagePattern":"Unexpected callback for asynchronous \\(nowait\\) operation\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pika/channel.py","lineNumber":1467,"sourceCode":"        :param acceptable_replies: A (possibly empty) sequence of\n            replies this RPC call expects or None\n        \"\"\"\n        assert method.synchronous, (\n            f'Only synchronous-capable methods may be used with _rpc: {method!r}'\n        )\n\n        # Validate we got None or a list of acceptable_replies\n        if not isinstance(acceptable_replies, (type(None), list)):\n            raise TypeError('acceptable_replies should be list or None')\n\n        if callback is not None:\n            # Validate the callback is callable\n            if not callable(callback):\n                raise TypeError('callback should be None or a callable')\n\n            # Make sure that callback is accompanied by acceptable replies\n            if not acceptable_replies:\n                raise ValueError(\n                    'Unexpected callback for asynchronous (nowait) operation.')\n\n        # Make sure the channel is not closed yet\n        if self.is_closed:\n            self._raise_if_not_open()\n\n        # If the channel is blocking, add subsequent commands to our stack\n        if self._blocking:\n            LOGGER.debug(\n                'Already in blocking state, so enqueueing method %s; '\n                'acceptable_replies=%r', method, acceptable_replies)\n            self._blocked.append([method, callback, acceptable_replies])\n            return\n\n        # Note: _send_method can throw exceptions if there are framing errors\n        # or invalid data passed in. Call it here to prevent self._blocking\n        # from being set if an exception is thrown. This also prevents\n        # acceptable_replies registering callbacks when exceptions are thrown","sourceCodeStart":1449,"sourceCodeEnd":1485,"githubUrl":"https://github.com/pika/pika/blob/34a407b24f08f2307578ceff870b6d7a12e7fdca/pika/channel.py#L1449-L1485","documentation":"_rpc enforces that a callback may only accompany non-empty acceptable_replies. A callback with empty/None replies is contradictory - there is no reply frame to dispatch to it (this is a nowait/asynchronous send), so pika raises ValueError to surface the inconsistency.","triggerScenarios":"Calling _rpc (or a channel method built on it) with a callback but acceptable_replies=None or []; mixing nowait=True with a completion callback.","commonSituations":"Requesting a callback on a nowait operation; a custom RPC helper that always attaches a callback regardless of replies.","solutions":["Either drop the callback, or supply the expected reply method class(es) in acceptable_replies","For nowait ops, pass callback=None","Do not set nowait=True when you need the reply"],"exampleFix":"# before (callback but no replies)\nchannel._rpc(method, on_reply, None)  # ValueError\n\n# after (choose one)\nchannel._rpc(method, None, None)              # fire-and-forget\nchannel._rpc(method, on_reply, [spec.X.Ok])   # expect a reply","handlingStrategy":"validation","validationCode":"def reconcile_callback_replies(callback, replies):\n    if callback is not None and not replies:\n        # cannot have a callback without replies; pick one\n        return None, replies  # drop callback for nowait\n    return callback, replies\n\ncb, replies = reconcile_callback_replies(callback, replies)\nchannel._rpc(method, cb, replies)","typeGuard":null,"tryCatchPattern":"try:\n    channel._rpc(method, cb, replies)\nexcept ValueError as e:\n    if 'Unexpected callback' in str(e):\n        channel._rpc(method, None, replies)  # nowait path\n    else:\n        raise","preventionTips":["Never pair a callback with empty/None acceptable_replies","For nowait operations, pass callback=None","Do not set nowait=True when you need the reply"],"tags":["channel","rpc","nowait","internal","validation"],"backgroundTag":null,"analyzedSha":"34a407b24f08f2307578ceff870b6d7a12e7fdca","analyzedAt":"2026-08-07T23:58:35.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}