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

Discord机器人command_prefix为NoneType的TypeError求助

Discord机器人前缀获取报错修复方案

问题背景

SQL基础薄弱,但判断问题并非出自SQL。Discord机器人曾正常运行一次,之后突然失效,抛出如下错误:

错误堆栈

Traceback (most recent call last):
  File "C:\Users\Mahdiyar\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\bot.py", line 1199, in get_prefix      
    ret = list(ret)  # type: ignore
          ^^^^^^^^^
TypeError: 'NoneType' object is not iterable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Mahdiyar\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\client.py", line 409, in _run_event
    await coro(*args, **kwargs)
  File "C:\Users\Mahdiyar\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\bot.py", line 1394, in on_message      
    await self.process_commands(message)
  File "C:\Users\Mahdiyar\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\bot.py", line 1389, in process_commands    ctx = await self.get_context(message)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Mahdiyar\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\bot.py", line 1288, in get_context     
    prefix = await self.get_prefix(origin)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Mahdiyar\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\bot.py", line 1206, in get_prefix      
    raise TypeError(
TypeError: command_prefix must be plain string, iterable of strings, or callable returning either of these, not NoneType

涉事代码

async def get_prefix(client, message):
    async with aiosqlite.connect("sqlite2023.db") as db:
        async with db.cursor() as cursor:
            await cursor.execute('SELECT prefix FROM prefix WHERE guild = ?' , (message.guild.id,))
            data = await cursor.fetchone()
            if data:
                return data
            else:
                try:
                    await cursor.execute('INSERT INTO prefix (prefix, guild) VALUES (? , ?)', ('!', message.guild.id,))
                    await cursor.execute('SELECT prefix FROM prefix WHERE guild = ?' , (message.guild.id,))
                    data = await cursor.fetchone()
                    if data:
                        cursor.execute('UPDATE prefix SET prefix = ? WHERE guild = ? ' , ('!',message.guild.id,))
                except Exception:
                    return '!'

@client.event #Client Statusa
async def on_ready():
    forever_print.start()
    asyncio.create_task(rich_presence())
    print("Client is online!")
    async with aiosqlite.connect("sqlite2023.db") as db:
        async with db.cursor() as cursor:
            await cursor.execute('CREATE TABLE IF NOT EXISTS prefix (prefix TEXT ,guild ID)')
        await db.commit()

问题诊断

  1. 函数返回值缺失:get_prefix的else分支中,若插入数据未触发异常,函数没有明确返回值,默认返回None,直接违反Discord.py对前缀的类型要求。
  2. 返回值类型错误:fetchone()返回元组(如('!',)),直接返回元组会被当作前缀列表处理,不符合预期,应返回字符串类型的前缀。
  3. 数据库操作不完整:INSERT执行后未调用await db.commit(),数据未持久化,下次查询仍返回空。
  4. 表结构语法错误:CREATE TABLE中的guild ID是无效语法,Discord服务器ID为整数,应定义为guild INTEGER。
  5. 无效冗余操作:INSERT成功后执行UPDATE完全多余,且该操作未加await,会引发异步错误。

修复代码

async def get_prefix(client, message):
    # 处理私信场景,避免message.guild为None报错
    if not message.guild:
        return '!'
    
    async with aiosqlite.connect("sqlite2023.db") as db:
        async with db.cursor() as cursor:
            await cursor.execute('SELECT prefix FROM prefix WHERE guild = ?', (message.guild.id,))
            data = await cursor.fetchone()
            
            if data:
                # 返回元组中的字符串前缀
                return data[0]
            else:
                try:
                    # 插入默认前缀
                    await cursor.execute('INSERT INTO prefix (prefix, guild) VALUES (? , ?)', ('!', message.guild.id))
                    # 提交更改确保数据持久化
                    await db.commit()
                    return '!'
                except Exception as e:
                    # 打印异常便于调试
                    print(f"插入前缀失败: {str(e)}")
                    return '!'

@client.event
async def on_ready():
    forever_print.start()
    asyncio.create_task(rich_presence())
    print("Client is online!")
    async with aiosqlite.connect("sqlite2023.db") as db:
        async with db.cursor() as cursor:
            # 修正表结构,guild字段类型为INTEGER
            await cursor.execute('CREATE TABLE IF NOT EXISTS prefix (prefix TEXT, guild INTEGER)')
        await db.commit()

关键修复点

  • 补全所有分支的返回值,确保函数不会返回None。
  • 将fetchone()的返回值从元组改为字符串(取第一个元素)。
  • 插入数据后添加await db.commit(),保证数据写入数据库。
  • 修正表结构中guild字段的类型为INTEGER,符合Discord ID的类型规范。
  • 增加私信场景处理,避免因message.guild为None导致的报错。
  • 移除冗余的UPDATE操作,并为所有异步数据库操作添加await。
  • 异常分支添加错误打印,方便排查问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:50:17