pika/pika · error · ValueError
Unexpected callback for asynchronous (nowait) operation.
Error message
Unexpected callback for asynchronous (nowait) operation.
What it means
_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.
Source
Thrown at pika/channel.py:1467
:param acceptable_replies: A (possibly empty) sequence of
replies this RPC call expects or None
"""
assert method.synchronous, (
f'Only synchronous-capable methods may be used with _rpc: {method!r}'
)
# Validate we got None or a list of acceptable_replies
if not isinstance(acceptable_replies, (type(None), list)):
raise TypeError('acceptable_replies should be list or None')
if callback is not None:
# Validate the callback is callable
if not callable(callback):
raise TypeError('callback should be None or a callable')
# Make sure that callback is accompanied by acceptable replies
if not acceptable_replies:
raise ValueError(
'Unexpected callback for asynchronous (nowait) operation.')
# Make sure the channel is not closed yet
if self.is_closed:
self._raise_if_not_open()
# If the channel is blocking, add subsequent commands to our stack
if self._blocking:
LOGGER.debug(
'Already in blocking state, so enqueueing method %s; '
'acceptable_replies=%r', method, acceptable_replies)
self._blocked.append([method, callback, acceptable_replies])
return
# Note: _send_method can throw exceptions if there are framing errors
# or invalid data passed in. Call it here to prevent self._blocking
# from being set if an exception is thrown. This also prevents
# acceptable_replies registering callbacks when exceptions are thrownView on GitHub (pinned to 34a407b24f)
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
Example fix
# before (callback but no replies) channel._rpc(method, on_reply, None) # ValueError # after (choose one) channel._rpc(method, None, None) # fire-and-forget channel._rpc(method, on_reply, [spec.X.Ok]) # expect a reply
Defensive patterns
Strategy: validation
Validate before calling
def reconcile_callback_replies(callback, replies):
if callback is not None and not replies:
# cannot have a callback without replies; pick one
return None, replies # drop callback for nowait
return callback, replies
cb, replies = reconcile_callback_replies(callback, replies)
channel._rpc(method, cb, replies) Try / catch
try:
channel._rpc(method, cb, replies)
except ValueError as e:
if 'Unexpected callback' in str(e):
channel._rpc(method, None, replies) # nowait path
else:
raise Prevention
- 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
When it happens
Trigger: Calling _rpc (or a channel method built on it) with a callback but acceptable_replies=None or []; mixing nowait=True with a completion callback.
Common situations: Requesting a callback on a nowait operation; a custom RPC helper that always attaches a callback regardless of replies.
Related errors
- acceptable_replies should be list or None
- callback should be None or a callable
- on_done arg must be callable, but got {on_done!r}
- delivery_tag must be an integer
- acceptable_replies should be list or None
AI-assisted analysis of pika/pika@34a407b24f (2026-08-07).
Data as JSON: /api/errors/6674f70e22025db6.
Report an issue: GitHub.