Errors

Every error wzgram raises lives in pyrogram.errors. They fall into three families: RPC errors that Telegram sent back, listener errors from listen(), and low-level protocol errors from the MTProto session.

from pyrogram.errors import FloodWait, RPCError

try:
    await app.send_message("me", "Hi")
except FloodWait as e:
    await asyncio.sleep(e.value)
except RPCError as e:
    print(e.ID, e.CODE, e.MESSAGE)

See Error Handling for the guide; this page is the hierarchy.


RPC errors

RPCError is the base of everything Telegram can answer with. Below it sits one class per HTTP-like status code, and below those, one class per specific error string:

RPCError
├── SeeOther            (303)  the request belongs on another datacenter
├── BadRequest          (400)  malformed or invalid request
├── Forbidden           (403)  not allowed
├── NotAcceptable       (406)  refused, usually needing user action
├── Flood               (420)  rate limited — FloodWait lives here
├── InternalServerError (500)  Telegram's problem, retry
└── ServiceUnavailable  (503)  Telegram is down or overloaded

Catching a category catches every specific error under it, including ones wzgram does not know about yet.

Each instance carries:

Attribute

Meaning

ID

the error string, e.g. FLOOD_WAIT_X

CODE

the numeric code, e.g. 420

NAME

the error name Telegram sent

MESSAGE

a human-readable description

value

the number embedded in the error, when there is one

FloodWait.value is the number of seconds to wait; on a SeeOther it is the datacenter to migrate to.

An error code the schema does not know raises the nearest category with UnknownError semantics and logs a warning naming the raw function that caused it.

Listener errors

Raised by listen(), ask() and the wait_for_* helpers — see Listeners.

ListenerError
├── ListenerTimeout        nobody answered in time; retrying is reasonable
├── ListenerStopped        the wait was cancelled or the client is stopping
└── ListenerLimitReached   the process-wide listener budget is exhausted

The distinction matters: except ListenerTimeout: retry is correct, while retrying a ListenerStopped spins against a client that is shutting down.

Protocol errors

Raised from the MTProto session rather than by Telegram’s application layer. You rarely catch these; they show up in logs when a connection misbehaves.

Error

Raised when

BadMsgNotification

the server rejected a message id or salt

SecurityError

a security check failed

SecurityCheckMismatch

a decrypted packet did not match what was expected

ReplayedMsgId

a message id was seen twice

CDNFileHashMismatch

a CDN chunk failed its hash check

Two ordinary Python errors are also load-bearing here, and the difference is deliberate:

  • ConnectionResetError — the connection dropped while a request was in flight. wzgram re-sends it on the new connection.

  • TimeoutError — the request really did time out. It is never used for a dropped connection, so “Request timed out” keeps meaning what it says.