April 19, 2026 • 版本: 2026.4.14

OpenClaw 2026.4.14 中 Telegram setMyCommands 在 Gateway 重启时未被调用

升级到 OpenClaw 2026.4.14 后,Telegram 机器人斜杠命令在 Gateway 重启时消失,因为 registerTelegramNativeCommands 初始化被跳过,导致命令菜单为空。

🔍 症状

  • 主要症状:网关重启后,所有 Telegram 机器人斜杠命令(42–58 条命令)从菜单中消失。
  • API 验证:getMyCommands Telegram 机器人 API 调用返回一个空列表:
    curl -s "https://api.telegram.org/bot<TOKEN>/getMyCommands"
    {"ok":true,"result":[]}
  • 日志缺失:网关启动日志中缺少预期的命令注册消息:
    {"subsystem":"gateway/channels/telegram"} Telegram menu text exceeded the conservative 5700-character payload budget; shortening descriptions to keep 58 commands visible.
  • 行为不一致:同一会话中的早期重启确实成功注册了命令,而后续重启则完全跳过注册。这表明存在非确定性的初始化失败。
  • 变通方案确认:手动调用 setMyCommands via the Bot API successfully restores commands,确认 Telegram API 本身功能正常,问题在于 OpenClaw 初始化序列。

用于症状确认的诊断命令

# 检查命令是否已注册(成功初始化后应返回非空数组)
curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMyCommands" | jq '.result | length'

# 预期输出:> 0 如果命令已注册
# 症状输出:0

🧠 根因分析

技术分析

根本原因在于 OpenClaw 2026.4.14(commit 323493f)中引入的竞态条件或初始化顺序依赖。registerTelegramNativeCommands 函数位于编译后的 bundle bot-BwMz6R6-.js 中,在网关启动序列期间未被调用。

故障序列

  1. 网关启动:OpenClaw 网关初始化所有已配置的通道,包括 Telegram 提供程序(基于 grammy)。
  2. 提供程序初始化:Telegram 提供程序在成功连接到 Telegram Bot API 时发出 ready 事件或等效的生命周期信号。
  3. 命令注册触发:registerTelegramNativeCommands 函数应在提供程序就绪时调用,以注册斜杠命令菜单。
  4. 故障点:在 2026.4.14 中,注册触发器存在以下问题之一:
    • 附加到在命令定义完全加载之前触发的事件
    • 受制于由于时序问题而评估为 false 的条件检查
    • 被静默失败的无处理 Promise 拒绝阻塞

架构不一致性

不一致的行为(某些重启有效,其他重启失败)表明这是一个与时间无关的竞态条件。可能的促成因素:

  • 异步初始化链:如果命令注册依赖于外部数据获取(例如,从数据库或配置存储加载命令定义),网络延迟变化可能导致注册在数据可用之前执行。
  • 事件处理器附加时序:在快速启动的实例上,ready 事件处理器可能在事件已经触发后才被附加。
  • 模块导入顺序:热重启和冷启动之间 ES 模块初始化顺序的差异。
  • 连接池状态:在长时间运行的网关会话中,累积的连接池状态可能影响初始化时序。

受影响的代码路径

// 受影响初始化路径的简化表示
async function initializeTelegramProvider(config) {
    const provider = new GrammyTelegramProvider(config);
    
    // 此处理器附加可能与 ready 事件竞争
    provider.on('ready', async () => {
        // 如果 'ready' 已触发,此块可能不执行
        await registerTelegramNativeCommands(provider, config.commands);
    });
    
    await provider.start(); // 在快速系统上 ready 事件在此处触发
}

🛠️ 逐步修复

立即变通方案

选项 1:手动命令注册(临时修复)
# Using curl to set commands directly via Telegram Bot API
curl -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/setMyCommands" \
  -H "Content-Type: application/json" \
  -d '{
    "commands": [
      {"command": "help", "description": "Show help information"},
      {"command": "status", "description": "Check system status"},
      {"command": "model", "description": "Switch AI model"},
      {"command": "cancel", "description": "Cancel ongoing operation"}
    ]
  }'

# 验证响应包含 {"ok": true, ...}
选项 2:Cron 任务作为权宜之计
# 添加到 crontab (crontab -e)
# 重启网关并立即重新注册命令
@reboot sleep 30 && /opt/openclaw/scripts/reregister-commands.sh
选项 3:通过 OpenClaw CLI 强制重新注册
# 如果 OpenClaw 提供 CLI 工具
openclaw commands register --channel telegram --force

# 或通过管理 API
curl -X POST "http://localhost:3000/api/channels/telegram/commands/reload" \
  -H "Authorization: Bearer ${MANAGEMENT_API_TOKEN}"

确定性修复:版本补救

步骤 1:识别当前版本
cat /opt/openclaw/package.json | grep '"version"'
# 或通过 CLI
openclaw --version
步骤 2:回滚到上一个稳定版本
# 如果使用 npm
npm install [email protected] --save

# 如果使用 Docker
# 编辑 docker-compose.yml
image: openclaw/openclaw:2026.4.13

# 重建并重启
docker-compose down && docker-compose up -d --build
步骤 3:升级到修复版本(可用时)
# 监控 OpenClaw GitHub releases 以获取 2026.4.15 或更高版本
# 一旦可用:
npm install openclaw@latest --save
# 或
docker-compose pull && docker-compose up -d

热修复:修补初始化顺序

警告:这是临时手动修复;在维护窗口期间应用。

# 定位编译后的 bundle
find /opt/openclaw -name "bot-BwMz6R6-.js" 2>/dev/null

# 备份原始文件
cp /opt/openclaw/dist/bot-BwMz6R6-.js /opt/openclaw/dist/bot-BwMz6R6-.js.bak

# 在提供程序初始化后添加同步注册调用
# 在现有 ready 处理器之前插入:
# 
# 之前(约第 XXX 行):
# provider.on('ready', async () => {
#
# 之后(补丁):
# // 立即注册尝试
# registerTelegramNativeCommands(provider, config.commands).catch(console.error);
# provider.on('ready', async () => {
#     await registerTelegramNativeCommands(provider, config.commands);
# });

🧪 验证

修复后验证步骤

  1. 重启网关
# 对于 systemd 管理的安装
sudo systemctl restart openclaw-gateway

# 对于 Docker
docker-compose restart gateway

# 对于 PM2
pm2 restart openclaw
  1. 检查网关日志中的命令注册
# 检查预期的日志消息
sudo journalctl -u openclaw-gateway -f | grep -i "setMyCommands\|menu text exceeded\|Telegram menu"

# 预期输出(成功):
# {"subsystem":"gateway/channels/telegram"} Telegram menu text exceeded the conservative 5700-character payload budget; shortening descriptions to keep 58 commands visible.
  1. 通过 Telegram Bot API 验证
# 获取已注册命令的数量
COMMAND_COUNT=$(curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMyCommands" | jq '.result | length')
echo "Registered commands: ${COMMAND_COUNT}"

# 预期:> 0(例如 42、58 等)
# 失败:0

# 用于调试的完整 API 响应
curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMyCommands" | jq .
  1. 在 Telegram 客户端中测试
# 打开 Telegram 并检查机器人的 / 菜单
# 所有之前可用的斜杠命令应该出现
# 测试一个已知命令(例如 /help)以确认功能
  1. 执行多次连续重启
# 验证跨重启的一致性(运行 3 次)
for i in 1 2 3; do
    echo "=== Restart $i ==="
    sudo systemctl restart openclaw-gateway
    sleep 10
    COUNT=$(curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMyCommands" | jq '.result | length')
    echo "Command count: $COUNT"
    if [ "$COUNT" -eq 0 ]; then
        echo "FAILURE: Commands not registered on restart $i"
        exit 1
    fi
done
echo "SUCCESS: Commands registered consistently across all restarts"

验证退出标准

  • ✅ 网关日志在启动时包含"Telegram menu text exceeded"消息
  • getMyCommands 返回非空数组
  • ✅ 所有预期命令出现在 Telegram 机器人的 / 菜单中
  • ✅ 多次连续重启后命令仍然存在
  • ✅ 连续重启测试脚本退出代码为 0

⚠️ 常见陷阱

  • 假设所有重启行为相同:该 bug 的表现不一致。几次成功的重启不能保证问题已解决。始终使用连续重启测试进行验证。
  • 忽略日志过滤:根据日志配置,相关日志消息可能会被截断或拆分为多行。使用 grep -i telegram 不带额外过滤器以确保捕获所有相关条目。
  • Docker 层缓存:如果使用 Docker,确保在版本更改后强制重建:
    docker-compose build --no-cache
    docker-compose up -d
  • 环境变量时序:TELEGRAM_BOT_TOKEN 环境变量必须在网关启动前设置。检查您的环境文件是否正确加载:
    # 验证环境已加载
    env | grep TELEGRAM
  • Node.js 版本交互:Node 22.22.1 可能表现出与其他版本不同的异步时序。使用与工作环境(升级前)相同的 Node 版本进行测试。
  • 网关高可用配置:在多实例设置中,确保命令注册是幂等的。重复的 setMyCommands 调用可能触发 Telegram 的速率限制。
  • 缺少优雅关闭:突然终止网关进程可能导致 Telegram Webhook 连接处于不一致状态。始终使用优雅关闭信号:
    kill -SIGTERM <pid>  # 首选
    # 避免:kill -SIGKILL <pid>
  • 命令描述长度:如果您添加了描述超过 256 个字符的自定义命令,Telegram API 将拒绝整个批次。"menu text exceeded"日志消息表示此保护措施已激活。
  • 防火墙/代理干扰:企业代理可能会延迟 Telegram API 响应,加剧竞态条件。测试直接连接:
    curl -v --max-time 10 "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe"

🔗 相关错误

  • UNAUTHORIZED (401) Bot API 调用 — 通常表示机器人令牌错误,不是此问题。如果遇到请验证令牌配置。
  • Too Many Requests (429) 来自 Telegram API — 在重复命令注册尝试期间进行速率限制。如果实施自动重新注册,请实施指数退避。
  • 升级后 getMyCommands 响应为空(Issue #4521) — 这是本指南记录的 bug 的主要症状。
  • 网关无法连接 Telegram 并显示 ETIMEDOUT — 网络连接问题,与命令注册 bug 无关,但可能同时出现。
  • 机器人令牌轮换后命令消失 — 使用新令牌时的预期行为;命令是令牌特定的。令牌轮换后重新注册。
  • Webhook 与 Polling 模式不一致 — 如果在 Telegram 连接模式之间切换,命令注册状态可能无法在转换期间正确保留。
  • 历史记录:2026.3.x 中的 setMyCommands 负载大小错误 — 之前的版本有相关 bug,其中 60+ 命令超过了保守的负载预算。这在 2026.4.14 中通过 5700 字符限制部分解决,但引入了初始化回归。

交叉引用

  • OpenClaw GitHub:搜索带有 telegram + commands 标签的问题以获取正在进行的补丁
  • grammy 文档:https://grammy.dev/plugins/commands — 机器人命令菜单注册 API 详情
  • Telegram Bot API:setMyCommands — 命令注册的官方 API 规范

依据与来源

本故障排除指南由 FixClaw 智能管线从社区讨论中自动合成。