You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用discord.py修改角色图标报错,求原因及解决方法

问题:Discord.py 修改角色图标时触发 TypeError 错误

我使用discord.py开发Discord机器人,编写了以下命令用于修改指定ID角色的图标:

@bot.command(name='role')
async def role(ctx, role_id, new_icon_url):

    new_icon_url = str(new_icon_url)
    if new_icon_url.count('<:') != 0:
        new_icon_url = new_icon_url.split(':')
        new_icon_url = new_icon_url[2]
        new_icon_url = new_icon_url.replace('>', '')
        new_icon_url = 'https://cdn.discordapp.com/emojis/%{placeholder}%.png'.replace('%{placeholder}%', new_icon_url)

    role = discord.utils.get(ctx.guild.roles, id=int(role_id))

    if role is not None:
        try:
            await role.edit(display_icon=new_icon_url)
            await ctx.send(f"Role icon for {role.name} has been updated.")
        except discord.errors.Forbidden:
            await ctx.send("I don't have the required permissions to edit role icons.")
    else:
        await ctx.send(f"Role with ID {role_id} not found.")

但执行命令时触发了如下错误:

Traceback (most recent call last):
  File "C:\Users\VosQu\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\discord\ext\commands\core.py", line 235, in wrapped
    ret = await coro(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\VosQu\OneDrive\Desktop\Brewy Poo\brew.py", line 271, in role
    new_icon_url = bytes(new_icon_url)
                   ^^^^^^^^^^^^^^^^^^^
TypeError: string argument without an encoding

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\VosQu\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\discord\ext\commands\bot.py", line 1350, in invoke
    await ctx.command.invoke(ctx)
  File "C:\Users\VosQu\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\discord\ext\commands\core.py", line 1029, in invoke
    await injected(*ctx.args, **ctx.kwargs)  # type: ignore
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\VosQu\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\discord\ext\commands\core.py", line 244, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: string argument without an encoding

原本预期命令能成功修改角色图标,但实际返回上述错误,请问原因是什么?


原因分析与修复方案

1. 直接错误原因:字符串转Bytes未指定编码

错误栈明确指向代码第271行的new_icon_url = bytes(new_icon_url)——Python中把字符串转成bytes对象必须指定编码格式(比如utf-8),否则会触发TypeError。如果这行是你主动添加的,要么删除它,要么修正为:

new_icon_url = bytes(new_icon_url, 'utf-8')  # 指定编码

但这只是解决了表面的语法错误,核心问题是你误解了role.edit()方法中display_icon参数的要求。

2. 核心问题:display_icon不支持直接传入URL

discord.py的Role.edit()方法的display_icon参数不接受普通URL字符串,它只接受以下三种类型的输入:

  • bytes:图片的二进制数据
  • io.BufferedIOBase:文件流对象(比如io.BytesIO)
  • str:Base64编码的图片字符串(格式为data:image/png;base64,xxxxxx)

3. 修复后的完整代码示例

要实现从URL修改角色图标的功能,你需要先下载图片内容,再转换成符合要求的格式传入。以下是使用aiohttp下载图片并以File对象传入的示例:

import aiohttp
from io import BytesIO
from discord import File

@bot.command(name='role')
async def role(ctx, role_id, new_icon_url):
    # 处理表情符号转CDN URL的逻辑
    if '<:' in new_icon_url:
        emoji_parts = new_icon_url.split(':')
        emoji_id = emoji_parts[2].replace('>', '')
        new_icon_url = f'https://cdn.discordapp.com/emojis/{emoji_id}.png'

    # 获取目标角色
    role = discord.utils.get(ctx.guild.roles, id=int(role_id))
    if not role:
        await ctx.send(f"找不到ID为{role_id}的角色。")
        return

    try:
        # 异步下载图片内容
        async with aiohttp.ClientSession() as session:
            async with session.get(new_icon_url) as resp:
                if resp.status != 200:
                    await ctx.send("图片下载失败,请检查URL是否有效。")
                    return
                image_data = await resp.read()
        
        # 将二进制数据包装成File对象传入
        await role.edit(display_icon=File(BytesIO(image_data), 'role_icon.png'))
        await ctx.send(f"{role.name}的角色图标已更新。")
    except discord.errors.Forbidden:
        await ctx.send("我没有修改角色图标的权限。")
    except Exception as e:
        await ctx.send(f"更新失败:{str(e)}")

4. 其他可选方案:使用Base64编码

如果你不想用File对象,也可以将图片转成Base64编码字符串传入:

import base64

# 在下载到image_data后:
base64_str = base64.b64encode(image_data).decode('utf-8')
await role.edit(display_icon=f"data:image/png;base64,{base64_str}")

内容的提问来源于stack exchange,提问作者VosQuz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 06:12:06