OpenClaw 2026.4.14 中 Telegram setMyCommands 在 Gateway 重启时未被调用
升级到 OpenClaw 2026.4.14 后,Telegram 机器人斜杠命令在 Gateway 重启时消失,因为 registerTelegramNativeCommands 初始化被跳过,导致命令菜单为空。
🔍 症状
- 主要症状:网关重启后,所有 Telegram 机器人斜杠命令(42–58 条命令)从菜单中消失。
- API 验证:
getMyCommandsTelegram 机器人 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. - 行为不一致:同一会话中的早期重启确实成功注册了命令,而后续重启则完全跳过注册。这表明存在非确定性的初始化失败。
- 变通方案确认:手动调用
setMyCommandsvia 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 中,在网关启动序列期间未被调用。
故障序列
- 网关启动:OpenClaw 网关初始化所有已配置的通道,包括 Telegram 提供程序(基于 grammy)。
- 提供程序初始化:Telegram 提供程序在成功连接到 Telegram Bot API 时发出
ready事件或等效的生命周期信号。 - 命令注册触发:
registerTelegramNativeCommands函数应在提供程序就绪时调用,以注册斜杠命令菜单。 - 故障点:在 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);
# });🧪 验证
修复后验证步骤
- 重启网关
# 对于 systemd 管理的安装
sudo systemctl restart openclaw-gateway
# 对于 Docker
docker-compose restart gateway
# 对于 PM2
pm2 restart openclaw- 检查网关日志中的命令注册
# 检查预期的日志消息
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.- 通过 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 .- 在 Telegram 客户端中测试
# 打开 Telegram 并检查机器人的 / 菜单
# 所有之前可用的斜杠命令应该出现
# 测试一个已知命令(例如 /help)以确认功能- 执行多次连续重启
# 验证跨重启的一致性(运行 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 规范