Reliability

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.