Search code examples
pythondiscorddiscord.pywebhookspycord

Unable to send a webhook only in one server


Code

webhooks = await message.channel.webhooks()
webhook = discord.utils.get(webhooks, name=message.author.display_name)
if webhook is None:
    webhook = await message.channel.create_webhook(name=message.author.display_name)
await webhook.send(content=content, username=message.author.display_name, avatar_url=message.author.avatar)
await message.delete()

Traceback

Ignoring exception in on_message
Traceback (most recent call last):

File "/app/.heroku/python/lib/python3.9/site-packages/discord/client.py", line 382, in _run_event
await coro(*args, **kwargs)

File "/app/cogs/events.py", line 105, in on_message
await webhook.send(content=content, username=message.author.display_name, avatar_url=message.author.avatar)

File "/app/.heroku/python/lib/python3.9/site-packages/discord/webhook/async_.py", line 1508, in send
raise InvalidArgument("This webhook does not have a token associated with it")
discord.errors.InvalidArgument: This webhook does not have a token associated with it

Webhooks are enabled in the intents and the text channel. This exception is only being raised in one server, it works fine in other servers.

I tested the same code on my local system, the client running on the local system sends the webhook without any troubles.


Solution

  • It's a bad idea to create every webhook itself - you can quickly hit the ratelimit of 10 webhooks per channel.

    Instead, the API allows you to use send with a custom username and avatar.
    In the current version of the discord client, clicking on the webhook will still show the fake user. There is no need to make an individual one for every user.

    You can then do something like this:

    async def impostor(ctx, user: discord.User, *, msg: str):
        hooks = await ctx.channel.webhooks()
        hook = utils.get(hooks, name='My Impostor Webhook')  # Change this to whatever you want, nobody will see it. This is only displayed to admins checking the webhook list and for the bot to find it again.
        if hook is None:
            hook = await ctx.channel.create_webhook(name='My Impostor Webhook', avatar=None, reason=None)
        await hook.send(content=msg, username=user.name, avatar_url=user.avatar_url)
    

    (note that in the newer versions this will be .avatar.url)