Skip to content

[Bug] sync_commands() 注册路径裸调用无防护,30034 配额耗尽时 AstrBot 启动崩溃(terminate 路径已防护) #8029

@RAUHODO

Description

@RAUHODO

What happened / 发生了什么

discord_platform_adapter.py 同一个文件里有两处 sync_commands() 调用:

  1. terminate() 路径(line 345-356):完整 try/except + asyncio.wait_for(timeout=10)
    任何错误降级为 warning

  2. register 路径(line 430):裸调用 await self.client.sync_commands()
    注释明明白白写"注意:这可能需要一些时间,并且有频率限制"
    但完全没有错误防护

结果:当 Discord 端返回 application-level error code 30034
("Max number of daily application command creates reached",每日 200 次配额耗尽)
时,register 路径的 exception 直接冒泡到 platform_adapter 启动流程,
让整个 AstrBot 启动失败。

注:30034 是 Discord 业务级配额,频繁重启 / 频繁修改 slash command 注册的
开发场景容易撞到(特别是 dev/staging 环境一天调试多次)。已注册的命令仍在
Discord 端有效,但 AstrBot 启动不来。

Reproduce / 如何复现?

路径 A(最直接,需要触发 30034):

  1. 部署 AstrBot + Discord adapter,启用 enable_command_register
  2. 频繁修改注册的 slash commands(一天 200 次以上不同的注册尝试)
  3. 之后任何重启都会撞 30034 直到次日配额重置

路径 B(代码层 self-evident):
直接对比 master HEAD b32cc8d 同一文件:

  • line 345-356 (terminate): try/except + wait_for 防护齐全
  • line 430 (register): 裸调用,注释还自己说"有频率限制"

问题不需要等到撞才能确认 —— 代码层就已经能看出对称漏洞。

AstrBot version, deployment method (e.g., Windows Docker Desktop deployment), provider used, and messaging platform used. / AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器

AstrBot: v4.22.3,master HEAD b32cc8d 同样未修
部署: Linux native + systemd unit
平台: Discord(启用 enable_command_register)
Provider: 与本 issue 无关(platform 层问题)

OS

Linux

Logs / 报错日志

本部署 4/01 之后 journalctl 已轮转过,无 30034 原始 log 残留。但本 bug
不依赖 log 证明——证据来自上游代码的 self-evident inconsistency:

文件: astrbot/core/platform/sources/discord/discord_platform_adapter.py
master HEAD: b32cc8d

terminate 路径(line 344-356)已加防护:

@override
async def terminate(self) -> None:
    ...
    if self.enable_command_register and self.client:
        try:
            await asyncio.wait_for(
                self.client.sync_commands(
                    commands=[],
                    guild_ids=[self.guild_id] if self.guild_id else None,
                ),
                timeout=10,
            )
            logger.info("[Discord] Commands cleaned up successfully.")
        except Exception as e:
            logger.warning(
                f"[Discord] Error occurred while cleaning up commands: {e}"
            )

register 路径(line 428-431)裸调用:

    # 使用 Pycord 的方法同步指令
    # 注意:这可能需要一些时间,并且有频率限制   ← 维护者明确知道
    await self.client.sync_commands()
    logger.info("[Discord] Command synchronization completed.")

Discord 30034 文档:
https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes
"Max number of daily application command creates has been reached"

修复建议: register 路径加同样的 try/except,建议 30034 单独识别记 warning,
其他异常仍 raise 保留 fail-fast 行为:

try:
    await self.client.sync_commands()
    logger.info("[Discord] Command synchronization completed.")
except Exception as _sync_err:
    if getattr(_sync_err, 'code', None) == 30034 or '30034' in str(_sync_err):
        logger.warning(
            "[Discord] 今日 slash command 注册配额已满(30034),已跳过同步。已注册的命令仍可用。"
        )
    else:
        raise

本地修复 4/早期 落地,跑了 1 个月稳定。

Are you willing to submit a PR? / 你愿意提交 PR 吗?

  • Yes!

Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:platformThe bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on.bugSomething isn't workingpriority: p1

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions