Most freely available APIs and commercial APIs have a rate limit. The rate limit’s there so that hackers or bots don’t abuse it, because if they send too many requests quickly, it could break the API endpoint. It can also be applied to user types, e.g., paying users usually have higher limits than free users. But sometimes, this becomes an issue for a genuine person who’s developing a product using these APIs.
In this post, we’ll look into dealing with Discord API rate limiting from a developer’s perspective. We will explore in detail two methods to solve the rate limit issue. The first method is synchronization with Redis, and the second method uses a global request proxy.
What Are Rate Limits?
Discord has different rate limits for routes and discord bots. On top of that, Discord also has a global limit of fifty requests per second. The rate limits are always given on the response headers, which can be found in the developer tools section of your browser. Generally, developers hit this rate limit when their community grows and their Discord bots need to process more requests.
The response header will look like this:
Now let’s understand what these terms mean. Here, X-RateLimit-Limit means the total number of requests we can make to this endpoint. The X-RateLimit-Remaining means the remaining requests available during the bucket time window before the limit is reset.
X-RateLimit-Reset gives the Epoch time when the rate limit will be reset. If you haven’t heard of it, Epoch time is the universal Unix time, which is the time elapsed since Jan 1, 1970. Many computer systems and software use this time, which can be easily converted into a human-readable format.
The X-RateLimit-Reset-After gives the time in seconds before our rate limit will be reset. The last thing here is X-RateLimit-Bucket,which is a random string given by Discord. This random string doesn’t mean anything, but it keeps track of this Discord rate limit. It’s a unique string, representing that the user has gotten rate-limited for their Discord channel.
What Happens When Rate Limits Are Exceeded?
Discord will return a 429 status code after reaching a rate limit. Your application must inspect the X-RateLimit-Reset-After header or retry_after from the body to check how long it needs to wait to retry the request.
An example response from a request being rate limited will look like the following:
What Is the Invalid Request Limit?
If a single IP address makes too many invalid HTTP requests from the browser, they’re restricted from accessing the Discord API. The limit is currently set at 10,000 per 10 minutes. This is a very high number and can only be made by larger applications, which should always have logging to avoid reaching this limit.
In the context of rate-limiting, the important status code is 429
- A 429 status can be avoided by always inspecting the rate limit, which was mentioned in the previous section.
Handling Rate Limits for Bots
The handling of rate limits for bots depends on the bot’s size. If the bot is small and created using discord.py, then the rate limit will automatically be handled by the bot. This library has built-in code which will never let your bot hit the rate limit.
Problems will be more likely to happen when the bot becomes larger. At that point, we would generally split our bot into multiple processes. We need to give each route a rate limit by dividing the global rate limit and then synchronizing the route rate limit with the global rate limit.
Below, we will learn two methods to solve the issue of rate-limiting. One is through synchronization with Redis, and the other is through a global request proxy.
Handling Rate Limits With Redis
We can synchronize the rate limit between processes by using a database like Redis. Here, we store the rate limit in the shared key-value storage of Redis so that all processes know about each other’s rate limit. How that works is detailed in the steps below.
- Before the request, the process checks whether Redis contains a key that shows that the global rate limit was touched.
- This process creates a key that identifies the request route.
- It checks the time to live for the request key in Redis.
- It also checks the remaining value for the request key in Redis.
- The process waits for the time to live to be over, once the remaining value is 0.
After Receiving Request Code 2XX
- The process gets the rate limit information from the response headers.
- It puts the remaining value into Redis, where the time to live is the X-RateLimit-Reset-After.
After Receiving Request Code 429
- The process checks whether the global rate limit was reached.
- If the global rate limit was reached: Process sets a key in Redis that indicates that the global rate limit was reached.
- If the per-route limit was reached: Process sets the remaining value for the request route in Redis to 0.
Ultimately, if a process will hit the rate limit, another process can start to take the further requests.
Handling Rate Limits With Global Request Proxy
Instead of storing a key-value pair in a Redis database, we can use a central proxy server, where all requests go through this server, and it handles the global rate limit. It can also handle the individual process rate limits.
One of the most popular free and open-source global request proxies is called twilight-http-proxy. It will synchronize the global and individual process rate limits for us automatically.
You can also use the reverse proxy feature of NGINX to achieve the same goal, as it allows setting of the global rate limit. The NGINX config will look like below.
One of the most popular free and open-source global request proxies is called twiight-http-proxy
This adds the global rate limit with limit_req_zone, where the max body size is 6MB. An additional 2000 requests will be queued if the global rate limit of forty requests per second is reached, and a response of a 697 status code will be given to all requests. The global rate limit will never be reached, and our Discord app will work great.
Conclusion
In this post, we’ve learned about rate limit issues in the Discord API. We also learned about rate limit exceeded messages and have looked into dealing with Discord API rate limiting from a developer’s perspective. We’ve learned about solving this issue with Redis or solving it through a central global proxy request server, with detailed steps provided for each.
Now you should have the information and tools you need to fix any Discord API rate limiting issues that you encounter, making working with the Discord API much easier. You could work toward avoiding hitting Discord API rate limits altogether by having a discord.py bot for smaller communities, and using the solutions with Redis and a central global proxy server for bigger communities.
To stay updated with our latest content, please
subscribe to our email updates or follow us on Twitter at @runmedev! Also, check out
Runme, a VS Code Extension that lets you run commands in READMEs with a click instead of tedious copy&pasting into a terminal.
Let us know what you think. Bye for now! 👋
This post was written by Nabendu Biswas. Nabendu has been working in the software industry for the past 15 years, starting as a C++ developer, then moving on to databases. For the past six years he’s been working as a web-developer working in the JavaScript ecosystem, and developing web-apps in ReactJS, NodeJS, GraphQL. He loves to blog about what he learns and what he’s up to.
My code (see below) was running fine, but then this error popped up and doesn’t go away:
"http.py", line 293, in static_login
data = await self.request(Route('GET', '/users/@me')
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/http.py", line 209, in request
raise HTTPException(r, data)
discord.errors.HTTPException: 429 Too Many Requests (error code: 0): "
I searched up the error, and I saw that people got it from running powerful programs on multiple servers, or people running the same code tons of times on a single one. But, I only run it on one server and it’s very simple code.
Here’s the code for reference (it’s running in repl.it) (the os.getenv is to hide the bot’s token):
import discord
import os
client = discord.Client()
@client.event
async def on_ready():
print ('We have logged in as {0.user}'.format(client))
@client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('$hello'):
await message.channel.send('Hello!')
client.run(os.getenv('TOKEN'))
Go to Discord_Bots
r/Discord_Bots
r/Discord_Bots
Non-official subreddit for Discord bot developement
Members
Online
•
by
JodeneBorg
How to limit discord’s HTTP error 429
i use discord.py to develop bots and i don’t know why but sometimes i get banned from the Api temporarily does anyone know any tips on limiting this? or a method on stopping this.
-Thanks for reading
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and
privacy statement. We’ll occasionally send you account related emails.
Already on GitHub?
Sign in
to your account
Closed
KsaRedFx opened this issue
May 29, 2020
· 52 comments
Closed
429 Rate Limits being hit constantly
#719
KsaRedFx opened this issue
May 29, 2020
· 52 comments
Comments
After running DiscordSRV for… months without issue, at 10pm EST on the 28th our consoles started flooding with messages like this;
[Fri, 29. May 2020 00:04:42 EDT WARN] [JDA] Encountered 429 on route /channels/:channel_id
[Fri, 29. May 2020 00:04:42 EDT WARN] [JDA] Encountered 429 on route /channels/:channel_id
Currently running the latest version from the Spigotmc page.
Unsure why this is happening, perhaps Discord changed their rate limits and for some reason DiscordSRV isn’t respecting it?
Seems to happen for both the console, and chat channel bridges.
Developer Edit:
Fix: Update DiscordSRV to 1.19.0
The latest snapshot produces… Similar yet slightly different results;
[DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket <SNIP>:guild_id:<SNIP>:webhook_id Retry-After: 147987 ms
I am having this issue as well. Will await a response from the dev(s).
I added «Encountered 429 on route» to the list of messages not sent across the Discord Console bridge just to suppress some spam to the console.
And, the latest snapshot has made the error significantly less frequent.
Discord appears to be acting up. As long as you are running the latest version (DiscordSRV v1.18.4 or a snapshot 1.19.0 build), we have no control over this. Nothing to do but wait it out.
Network owners (Those that use Bungeecord) can try splitting up their instances so each backend server is operating under their own token, however given how even individual servers are reporting issues, this likely won’t fix it.
Also having this issue, for what it’s worth. It’s been a really good plugin so far! Appreciate there’s not much to be done right now, will attempt KsaRedFx’s quick fix of muting the message… as soon as I can figure out how to do that >_<
That can be done by adding "Encountered 429" in the DiscordConsoleChannelDoNotSendPhrases option and running /discordsrv reload afterwards.
Wouldn’t recommend it as a long term solution, however. Remove it as soon as discord seems to stop acting up.
Ah you’re a star, many thanks! I’ll keep tabs and disable once this has blown over, thank you very much =)
Same problem on our server. Thanks @granny for the tip
Hey, some users reported that using development builds helped with this problem. Please try using a development build from snapshot.discordsrv.com Now in 1.19.0+ https://get.discordsrv.com & react to this message with a 👍 if updating resolved the issue and 👎 if you’re still getting the messages after the update
KsaRedFx, pizzanakin, tytech038, CruxCraft, evlyou666, asciidude, s3677729, davipatricio, viminio, TheChaosCode, and santicsls reacted with thumbs down emoji
Having this issue as well.
I have to correct myself. The message continues to come. But at longer intervals.
Do we have any confirmation that this is an issue on Discord’s side? Their status page says everything is normal, and after ~12 hours I would expect that to have updated if there was an issue. But on the other hand I also can’t find any announcements saying they would be adjusting any limits.
And yes, I’m still getting the error after updating to the latest snapshot, though it may be less frequent. it was sporadic before, and haven’t been running the snapshot long enough to get a real sense of the prevalence yet.
Edit: Per Vankka’s comment, yes, the new error is a 429 on PATCH /channels instead of «429 on route /channels/…»
Discord doesn’t announce when they change rate limits, on releases the ratelimit gets hit on /channels/:channel_id where as on dev builds, it’s PATCH /channels/:channel_id (and a ‘bucket’ that’s seemingly to do with webhooks). It might not neccaserily be a Discord issue but they most likely changed the ratelimits to be a lot lower than before
JDA has its own rate limiting functionality, perhaps updating the JDA version will fix this issue?
1 similar comment
JDA has its own rate limiting functionality, perhaps updating the JDA version will fix this issue?
c590c3e Might’ve fixed this, please try dev builds again, same url
still getting it. But definitely seems not as frequent as it was with the old build (the latest stable, not the dev build)
how many times, is it still frequent?
With the last dev build, the messages were
May 29 15:49:14 mc1 minecraft[29248]: [15:49:14 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:710557529989709867:webhook_id Retry-After: 519087 ms
May 29 15:59:14 mc1 minecraft[29248]: [15:59:14 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:710547160331976736:webhook_id Retry-After: 548897 ms
May 29 15:59:14 mc1 minecraft[29248]: [15:59:14 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:710557529989709867:webhook_id Retry-After: 519108 ms
With the new build they’re
May 29 16:16:39 mc1 minecraft[29685]: [16:16:39 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:710557529989709867:webhook_id Retry-After: 74233 ms
May 29 16:26:39 mc1 minecraft[29685]: [16:26:39 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:710557529989709867:webhook_id Retry-After: 74354 ms
May 29 16:26:39 mc1 minecraft[29685]: [16:26:39 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:710547160331976736:webhook_id Retry-After: 104104 ms
Note that the Retry-After values are much lower. So it seems it isn’t hitting it as hard.
Oh, and something I just noticed, those messages seem to be 10 minutes apart every time. Is there some sort of scheduled task every 10 minutes that executes a bunch of calls?
it’s gotten a lot better now. still a few messages here and there but otherwise it’s fixed with the new dev version
I see similar results with the previous dev build from yesterday. Intervals of 10 minutes.
I am waiting for the messages to come through in the latest dev version to confirm.
Can confirm that it is still 10 minute intervals for the message, as phemmer said.
As a side note, I do see that Vanish is no longer respected in the develop versions… But that’s for another ticket.
Just to check, those that are still experiencing 429’s on latest development builds, do you have webhooks enabled (Experiment_WebhookChatMessageDelivery)?
I am not
Experiment_WebhookChatMessageDelivery: false
Experiment_WebhookChatMessageUsernameFormat: "%displayname%"
Experiment_WebhookChatMessageUsernameFromDiscord: false
KsaRedFx, what’s your 429’s route? Can you paste the log line here, just wanna check if it’s the same one others are getting
I reported the bug, and included my routes above…
But here’s the latest in the latest build
[12:57:14 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:591365675357044767:webhook_id Retry-After: 599877 ms
Thanks, so I must be completely on the wrong trail about it having something to do with webhooks. the ‘bucket’ ending with :webhook_id made me think that might’ve been the issue, time to dig deeper
Interestingly enough, despite the fact that experimental websocket is off, I still get
[JDA] Got disconnected from WebSocket (Code: 4000). Attempting to resume session
Oh my bad.
Also it’s still every 10 minutes.
[13:09:28 INFO]: The DiscordSRV config & lang have been reloaded.
[13:17:15 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:591365675357044767:webhook_id Retry-After: 599897 ms
[13:27:15 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:591365675357044767:webhook_id Retry-After: 599828 ms
[13:37:15 WARN]: [DiscordSRV] [JDA] Encountered 429 on route PATCH/channels/{channel_id} with bucket 9852e1a53c06ffc5a89d65fef85ca4ce:guild_id:591365675357044767:webhook_id Retry-After: 599850 ms
Update: looks like it is to do with the Topic Updater from my tests
So… that means what? can you easily remove/disable your tests?
Can be fixed on development builds by setting ChannelTopicUpdaterRateInMinutes to 10 and running /discord reload. Development builds (and the upcoming 1.19.0 will) enforce a 10 minute minimum for that now, too
But get still this messages. Do I need to use the latest dev build?
You might still run into some messages (especially during start & shutdown (and right after changing the config option)), but while the server is running, you shouldn’t run into the messages.
how long does «right after changing» usually take?
For the message to popup? As long as the remaining time to the next topic updater update was left at the time. When it starts using the new value of 10 minutes, it would only popup when the server starts & stops (and shutdown topics are enabled)
Okay, never mind…
The messages just stopped to spam in the console.
This was referenced
May 30, 2020
Hey guys, I am too getting this… Have noticed that the Channel topic isn’t updating anywhere near as frequent as before… Getting spammed with messages however everything else seems to be functional.
Edit: Ah looks like that was mentioned above too 
I still have this issue.
ConfigVersion: 1.18.4
after an update to 1.19 build, i still have the issue until i decided to stop my vps and update everything on it. I restarted my server (1 bungee and 4 servers) and no more issue. Don’t know if this could help but i hope so 
I created this discord bot, that I only use, which basically gets the voice chat of the author of the command, gets the activity being played in the voice channel, and change the name of the channel accordingly. I have no clue, why I’m getting this 429, Also it’s my first time using discord.py so I may have used something wrong. Here is the code:
import asyncio
import discord
from discord.ext import commands
token = 'Token'
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='!', intents=intents)
async def my_task(ctx):
voice_channel = ctx.author.voice.channel
while True:
if activities := [a.name for m in voice_channel.members for a in m.activities]:
most_common_activity = max(set(activities), key=activities.count)
await voice_channel.edit(name=f"{most_common_activity}")
else:
await voice_channel.edit(name="Other Games")
await asyncio.sleep(15)
@bot.command()
async def set_channel_activity(ctx):
bot.loop.create_task(my_task(ctx))
bot.run(token)

