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

discord.py Cogs开发中on_guild_join触发Guild无guild属性报错的修复

问题定位

直接触发当前堆栈的错误

on_guild_join是discord.py内置网关事件,事件触发时传入的第一个参数就是机器人刚加入的Guild对象本身,不存在命令上下文(ctx)。原代码错误将传入的Guild对象当作ctx实例,调用ctx.guild属性,自然抛出AttributeError: 'Guild' object has no attribute 'guild'。

修复上述报错后会依次触发的隐藏问题

  • 作用域混乱:代码中多处引用未定义的member变量,实际操作对象就是事件传入的Guild实例
  • 对象访问逻辑错误:将局部赋值的变量(如Muted_role、verify_role)错误绑定到不存在的ctx对象上调用,例如写ctx.Muted_role
  • 流程缺失:判断Tickets分类不存在时调用创建方法,但创建后没有将返回的分类对象赋值回ticket_category,后续统计分类子频道数量时会操作空对象
  • API属性拼写错误:查找频道时使用guild.channel,实际Guild类的全频道列表属性是guild.channels(复数形式)
  • 前置依赖缺失:代码尝试获取名为"Member"的验证角色,但从未在流程中创建该角色,通过工具方法查到的只会是空值,对空值对象设置权限会直接报错
  • 冗余操作:创建Muted角色后又遍历全服角色查找刚创建的对象,完全可以直接接收create_role方法的返回值,省去查找步骤
  • 权限操作对象错误:设置语音频道权限时,引用了不存在的ctx.guild.verify_role属性,实际要操作的是之前获取的Member角色对象
  • 消息发送逻辑错误:原代码直接调用ctx.send()发送嵌入消息,但机器人刚入服时不存在可直接发送消息的上下文,既没有默认发送渠道,也没有权限保证
  • 全局变量缺失:嵌入消息footer中引用的client对象未在Cog作用域内定义,会抛出NameError
修复后的可运行实现
import discord
from discord.ext import commands

class WelcomeCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.Cog.listener()
    async def on_guild_join(self, guild: discord.Guild):
        # 创建Muted角色,直接接收返回值,无需二次遍历查找
        muted_role = await guild.create_role(name="Muted")
        # 为Muted角色配置禁言类权限
        await muted_role.set_permissions(
            send_messages=False,
            add_reactions=False,
            create_public_threads=False,
            create_private_threads=False,
            send_messages_in_threads=False
        )

        # 获取或创建Member验证角色
        verify_role = discord.utils.get(guild.roles, name="Member")
        if not verify_role:
            verify_role = await guild.create_role(name="Member")
        # 为Member角色配置基础发言、连接权限
        await verify_role.set_permissions(
            send_messages=True,
            connect=True
        )

        # 获取或创建Tickets频道分类
        ticket_category = discord.utils.get(guild.categories, name="Tickets")
        if not ticket_category:
            ticket_category = await guild.create_category_channel(name="Tickets")

        # 创建欢迎文本频道
        await guild.create_text_channel(name="welcome")

        # 构建入服欢迎嵌入消息
        guild_join_embed = discord.Embed(title="Thanks for adding me")
        guild_join_embed.add_field(
            name="Thanks for adding me!",
            value="It helps alot. I will provide my best support",
            inline=True
        )
        guild_join_embed.set_footer(text=f"Right now I am in {len(self.bot.guilds)} guilds/servers")

        # 校验系统频道权限后再发送欢迎消息,避免无权限报错
        if guild.system_channel and guild.system_channel.permissions_for(guild.me).send_messages:
            await guild.system_channel.send(embed=guild_join_embed)

        # 配置统计类语音频道的基础权限覆盖:默认角色、Member角色均无法连接
        stat_channel_overwrites = {
            guild.default_role: discord.PermissionOverwrite(connect=False),
            verify_role: discord.PermissionOverwrite(connect=False),
            guild.me: discord.PermissionOverwrite(connect=True)
        }
        # 创建三类统计语音频道,创建时直接写入权限配置,无需二次查找修改
        await guild.create_voice_channel(
            name=f"Total Member Count: {guild.member_count}",
            overwrites=stat_channel_overwrites
        )
        await guild.create_voice_channel(
            name=f"Boost Count: {guild.premium_subscription_count}",
            overwrites=stat_channel_overwrites
        )
        await guild.create_voice_channel(
            name=f"Ticket Count: {len(ticket_category.channels)}",
            overwrites=stat_channel_overwrites
        )

注意事项

  • 机器人邀请时必须携带Manage Server、Manage Roles、Manage Channels权限,且自身最高角色的位置高于所有需要创建、修改权限的角色,否则所有创建操作会被Discord API拦截
  • 上述代码中的权限参数仅覆盖原业务逻辑涉及的范围,可根据实际需求调整细粒度权限
  • 统计类语音频道的数值不会自动实时更新,若需要同步服务器实时数据,需额外搭配定时任务逻辑,定期修改频道名称完成数值刷新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.31 01:24:01