⚠️ Errors#

Exceptions in pywa are a key mechanism for letting you know what went wrong and why. They appear in two main ways:

  1. Raised exceptions — when something fails immediately (e.g., invalid parameters).

  2. Returned errors — when the API reports an error asynchronously via a message status update.


Basic Example#

Most exceptions are raised directly when you attempt an invalid action:

import logging
from pywa import WhatsApp, types, errors

wa = WhatsApp(...)

try:
    wa.send_message(..., buttons=[
        types.Button(title="click 1", callback_data="click"),
        types.Button(title="click 2", callback_data="click"),  # ⚠️duplicate callback_data
    ])
except errors.InvalidParameter as e:
    logging.error(f"Duplicated `callback_data` in buttons: {e}")

Message Status Errors#

Some errors are not raised immediately but instead appear as part of a MessageStatus update.

For example:

  • Sending a non-template message outside the 24h conversation windowReEngagementMessage

  • Sending invalid media (wrong file type, too large, invalid URL, etc.) → MediaUploadError

These errors surface in the status update rather than raising an exception directly.

That’s why it’s important to always register a handler for failed message statuses:

import logging
from pywa import WhatsApp, types, filters

wa = WhatsApp(...)

@wa.on_message_status(filters.failed)
def handle_failed_message(client: WhatsApp, status: types.MessageStatus):
    logging.error("Message failed to send to %s: %s",
        status.sender, status.error
    )

Handling Specific Errors#

You can also filter and handle specific error types:

 1import logging
 2from pywa import WhatsApp, filters, errors
 3
 4wa = WhatsApp(...)
 5
 6wa.send_message(to="972501234567", text="Hello")  # 24h window closed
 7wa.send_image(  # nonexistent image
 8    to="972501234567",
 9    image="https://example.com/this-image-does-not-exist.jpg",
10    caption="Not found"
11)
12wa.send_document(  # file too large
13    to="972501234567",
14    document="https://example.com/document-size-is-too-big.pdf",
15    filename="big.pdf"
16)
17
18@wa.on_message_status(filters.failed_with(errors.ReEngagementMessage))
19def handle_failed_reengagement(client: WhatsApp, status: types.MessageStatus):
20    logging.error("Message failed to send to %s: %s",
21        status.from_user.wa_id, status.error
22    )
23
24@wa.on_status_message(filters.failed_with(errors.MediaUploadError))
25def handle_failed_sent_media(client: WhatsApp, status: types.MessageStatus):
26    logging.error("Message failed to send to %s: %s",
27        status.from_user.wa_id, status.error
28    )
29    status.reply_text("Sorry, I can't upload this file")
30
31@wa.on_status_message(filters.failed_with(errors.MediaDownloadError))
32def handle_failed_received_media(client: WhatsApp, status: types.MessageStatus):
33    logging.error("Got a media download error from %s: %s",
34        status.from_user.wa_id, status.error
35    )
36    status.reply_text("Sorry, I can't download this file")

Incoming Errors (Unsupported Messages)#

If a user sends an unsupported message type (e.g., poll), you’ll receive a Message with type UNSUPPORTED and an error of UnsupportedMessageType.

from pywa import WhatsApp, types, filters

wa = WhatsApp(...)

@wa.on_message(filters.unsupported)
def handle_unsupported_message(client: WhatsApp, msg: types.Message):
    msg.reply_text("Sorry, I don't support this message type yet")

Catching All Exceptions#

Since all exceptions inherit from WhatsAppError, you can catch everything with one block:

1from pywa import WhatsApp, errors
2
3wa = WhatsApp(...)
4
5try:
6    wa.send_message(...)
7except errors.WhatsAppError as e:
8    print(f"Error: {e}")

Base Exception#

class pywa.errors.WhatsAppError#

Bases: Exception

Base dataclass for WhatsApp errors.

Variables:
  • code (int) – The error code.

  • message (str) – The error message.

  • details (str | None) – The error details (optional).

  • fbtrace_id (str | None) – The Facebook trace ID (optional).

  • href (str | None) – The href to the documentation (optional).

  • raw_response (httpx.Response | None) – The httpx.Response obj that returned the error (optional, only if the error was raised from an API call).

  • subcode (int | None) – The error subcode (optional).

  • type (str | None) – The error type (optional).

  • is_transient (bool | None) – Whether the error is transient (optional).

  • user_title (str | None) – The user-facing title for the error (optional).

  • user_msg (str | None) – The user-facing message for the error (optional).


Categories of Exceptions#

All exceptions fall into one of these categories: