Flood waits & retries
Telegram rate-limits aggressive clients by returning FLOOD_WAIT_X — wait X seconds before retrying. gogram absorbs small waits silently; bigger ones bubble up to your code.
What a flood wait is
Every method has its own per-account and per-peer rate limits. Cross one and the server returns FLOOD_WAIT_X where X is the number of seconds you must wait before the same method (with the same arguments) will succeed. The limit is global for the account; restarting your process does not reset it.
Two siblings exist:
FLOOD_PREMIUM_WAIT_X— same idea, applied to premium-only methods.STORY_SEND_FLOOD_WEEKLY_X/_MONTHLY_X— story-posting quotas.
What the client handles for you
With SleepThresholdMs set (default 60 seconds), every flood wait shorter than that is absorbed: gogram sleeps, then retries the call. Your code never sees the error.
Longer waits surface as a regular ErrResponseCode so you can decide what to do.
client, _ := telegram.NewClient(telegram.ClientConfig{
// ...
SleepThresholdMs: 60_000,
FloodHandler: func(err error) bool {
log.Println("flood wait:", err)
return true // sleep and retry
},
})client, _ := telegram.NewClient(telegram.ClientConfig{
// ...
SleepThresholdMs: 60_000,
FloodHandler: func(err error) bool {
log.Println("flood wait:", err)
return true // sleep and retry
},
})Handling them explicitly
When you want full control:
_, err := client.SendMessage(peerID, msg)
var rpc *gogram.ErrResponseCode
if errors.As(err, &rpc) && strings.HasPrefix(rpc.Message, "FLOOD_WAIT") {
secs := rpc.AdditionalInfo.(int)
log.Printf("rate-limited, sleeping %d s", secs)
time.Sleep(time.Duration(secs) * time.Second)
// retry
}_, err := client.SendMessage(peerID, msg)
var rpc *gogram.ErrResponseCode
if errors.As(err, &rpc) && strings.HasPrefix(rpc.Message, "FLOOD_WAIT") {
secs := rpc.AdditionalInfo.(int)
log.Printf("rate-limited, sleeping %d s", secs)
time.Sleep(time.Duration(secs) * time.Second)
// retry
}Sleeping in your own goroutine is fine. Just do not retry too quickly — consecutive retries inside the original wait window only extend the wait.
Slowmode
_, err := client.SendMessage(peerID, msg)
if errors.As(err, &rpc) && strings.HasPrefix(rpc.Message, "SLOWMODE_WAIT") {
secs := rpc.AdditionalInfo.(int)
// queue the message until the slowmode window passes
}_, err := client.SendMessage(peerID, msg)
if errors.As(err, &rpc) && strings.HasPrefix(rpc.Message, "SLOWMODE_WAIT") {
secs := rpc.AdditionalInfo.(int)
// queue the message until the slowmode window passes
}Slowmode is an admin-configured per-chat cooldown that limits how often each user can post. Hitting it returns SLOWMODE_WAIT_X. Bots are usually exempt when they are admins; users always have to wait the window out.
Practical rate limits
Approximate limits; treat as rules of thumb, not contracts:
- ~30 messages per second across all chats for a bot.
- ~1 message per second per chat (more triggers per-chat flood waits even if global capacity is fine).
- ~20 group/channel posts per minute.
- ~5 edits per second per chat.
- Resolve calls (
contacts.resolveUsername,contacts.resolvePhone) tighten down to a few per second.
