Discord Rate Limits — The One That Locks You Out Isn't the Obvious One

·5 min read·Updated
discordbotsrate-limitstroubleshootingreliability

Discord's headline limit is generous and rarely the problem: "All bots can make up to 50 requests per second to our API" (Discord docs), on top of per-route buckets that your library almost certainly handles for you. The limit worth designing around is a different one. IP addresses that make too many invalid requests get temporarily restricted from the API — currently 10,000 per 10 minutes — and an "invalid request" means any 401, 403, or 429. That's the catch: a bot with a stale token, or one hitting a permission error on every message in a busy server, racks those up without ever going near 50 requests a second.

The normal limits, briefly

Your library handles these. Discord returns headers on every response — X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-RateLimit-Reset-After, X-RateLimit-Bucket, and X-RateLimit-Scope — and when you exceed a limit you get a 429 with a retry_after telling you exactly how long to wait.

The only rule that matters: use the value Discord gives you. The docs say to "rely on the Retry-After header or retry_after field to determine when to retry". A fixed one-second sleep is a guess, and a guess that's too short converts one 429 into several.

If you're using a maintained library, you get bucket handling for free. If you're calling the HTTP API directly with a bare loop — which generated code sometimes does for a single endpoint — you own all of this yourself, and that's usually the wrong trade.

The invalid request limit

Here's the one to internalise:

IP addresses that make too many invalid HTTP requests are automatically and temporarily restricted from accessing the Discord API. Currently, this limit is 10,000 per 10 minutes. An invalid request is one that results in 401, 403, or 429 statuses.

Three things follow, and none of them are obvious.

A 429 is itself an invalid request. So a retry loop that ignores retry_after doesn't just get rate limited — it accumulates toward a restriction. Rate limiting is designed to be survivable; ignoring it is what turns it into an outage.

A 403 counts, and 403s repeat. Missing Permissions isn't a transient failure — it will fail identically every time. A handler that tries to post to a channel it can't write to, running on every message in an active server, is a 403 factory. Ten thousand sounds like a lot until something fires per-message.

A 401 counts, and 401s are permanent too. A bot running with a revoked or rotated token will fail every single request. If it also retries, it's generating invalid requests as fast as it can.

The pattern across all three: the limit punishes repetition of errors that will never succeed. Transient failures are fine. Loops around permanent ones are not.

Why this is worse on a container platform

The restriction applies to an IP address, not to your bot. Your app doesn't choose the address its requests leave from, and you can't change it on demand — so if you trip this, the remedy is to stop making the requests and wait it out.

That makes prevention the entire strategy. There's no equivalent of "restart it and try again", and a restart-happy app makes things worse rather than better: a crash loop restarts your process every few seconds, and if the crash happens after your bot starts making failing API calls, each cycle contributes another batch.

That's the second reason to stop a crash-looping bot rather than leaving it running while you debug — the first being the IDENTIFY allowance.

Treat 401 and 403 as bugs, not errors

The single most useful change is to stop retrying failures that can't succeed.

  • On 403 — log it once with the channel and the permission, and don't try that operation again for that channel. A clear log line beats a hundred identical ones.
  • On 401 — stop. Don't retry, don't reconnect in a loop. A 401 means your token is wrong or revoked, and no amount of retrying fixes it. Exit with a clear message so the restart machinery makes it visible.
  • On 429 — wait exactly as long as Discord asked, then continue.

A useful reflex: any error handler that retries should ask "could this succeed on the next attempt?" If the answer is no, the right behaviour is to record it and stop.

Watch for the amplifiers

Some shapes generate invalid requests far faster than others:

  • Per-message handlers in busy servers. Anything that runs on every message multiplies whatever it does by your traffic.
  • Bulk operations on startup. Syncing commands, editing many channels, or backfilling on every boot — combined with restarts, that's a lot of requests you didn't intend.
  • Fan-out loops. "For every guild, do X" turns one bad assumption into hundreds of failures.
  • Aggressive reconnects written by hand, which the restart machinery already handles for you.

Check the logs before you assume

If your bot suddenly can't reach the API, look at the logs for what preceded it. A wall of identical 403s or 401s is the signature. Rate-limit problems announce themselves as repeated failures long before they become a restriction — which means they're catchable if you log status codes at all.

FAQ

What's Discord's rate limit for bots?

Fifty requests per second globally, plus per-route buckets communicated through X-RateLimit-* headers.

What is the invalid request limit?

Ten thousand invalid requests per ten minutes from one IP results in a temporary restriction. Invalid means a 401, 403, or 429 response.

Does getting rate limited count against it?

Yes — a 429 is an invalid request. Ignoring retry_after and retrying immediately makes a temporary limit into a bigger problem.

Why would a permission error get me banned?

Because 403s count and permission errors repeat forever. A handler running per message in a busy server can generate them very quickly.

Can I just restart or redeploy to fix it?

No. The restriction is tied to an IP address you don't control, so the fix is to stop making the failing requests and wait.

How should I retry?

Only for transient failures, and on a 429 wait exactly as long as Discord says. Never retry a 401, and don't retry a 403 for the same operation.

Wrapping up

Almost every bot stays comfortably inside Discord's throughput limits, so the rate-limit documentation reads like something you can skim. The part that matters isn't about volume at all — it's about repetition. Ten thousand failures in ten minutes is easy to reach when the failure is permanent and your code keeps asking anyway. Make permanent errors stop, respect retry_after exactly, and don't leave a broken bot looping while you work out what's wrong.