Error Handling

View as Markdown

Operational failures (success=false, timeouts) return a CommandResult or SendMessageResult - inspect the return value. Exceptions cover connection loss, invalid state, and authentication or session errors. Most call commands do not raise when answer() or connect() fails; they return a falsy CommandResult (if not result: works). WhatsApp send failures stay on SendMessageResult; check result.success (do not use if result:). Unsupported message types raise MessageError.

Exception hierarchy (selected)

Catch AgentDuetError for any SDK error, or a subclass for finer control.

ErrorWhen
AgentDuetErrorBase for all SDK errors
TransportErrorSession-manager or media connection problems
RequestTimeoutErrorSession-manager request got no response (link up, server silent). Not a subclass of TransportError.
AuthenticationErrorAPI key, token, or mTLS failure
CallErrorBase for call errors
CallClosedErrorCall over / media lost mid-op - stop working on that call
CallStateErrorOperation in an incompatible state (e.g. to_json() after media opens)
CallCommandError / CallCommandTimeoutErrorUsually surfaced as CommandResult
SessionErrorBase for session problems
SessionAlreadyExistsError / SessionNotFoundErrorSession id conflicts / missing
SubscriberMismatchErrorSession subscriber ≠ call subscriber
ParticipantsFullErrorSession at participant cap
CallNotFoundErrorNo pending call for id
ChannelNotConfiguredErrorRequired channel (for example WhatsApp) is not configured
MessageErrorUnsupported type passed to send_message()
QuotaExceededError / OutboundOverflowError / ForbiddenError / InvalidRequestErrorRequest-level rejections
BufferFullErrorOutgoing audio buffer full - throttle producer

Unanswered connect() / dial()

result = await call.connect(ring_time_seconds=30)
if not result:
if result.error_code == "CALL_UNANSWERED":
await call.disconnect()
else:
logger.error(
"Connect failed: %s (%s)", result.error_message, result.error_code
)

The call can stay active after CALL_UNANSWERED - retry, try another number, or end it.

WhatsApp send failures

result = await session.send_message(msg)
if not result.success:
logger.error(
"Send failed: %s (%s)", result.error_code, result.error_content
)
MessageErrorCodeMeaning
QUOTA_EXCEEDEDMessage sending limit exceeded for this connector
CHANNEL_NOT_CONFIGUREDThe session channel is not configured for messaging
REMOTE_ERRORThe provider (for example, Meta/WhatsApp) rejected the message
INVALID_REQUESTRequest payload format or structure is invalid
SESSION_BUSYThe session is bound to another live connection
SESSION_NOT_FOUNDThe session id does not exist on the server
SESSION_CLOSEDThe session has already closed
SESSION_ALREADY_EXISTSA session with that id already exists
SUBSCRIBER_MISMATCHThe subscriber does not match the session
PARTICIPANTS_FULLThe session already holds the maximum participants
CALL_NOT_FOUNDNo pending call for the given id
UNKNOWNUnrecognized code (forward-compatible fallback)

See WhatsApp Messaging.

Audio loops

try:
async for chunk in call.caller.audio_stream():
await call.send_audio(chunk)
except CallClosedError:
pass # normal end

Next Step