Telegram: commands.native 在启动时未能注册 setMyCommands
尽管在 OpenClaw 2026.4.14 中的配置正确,但原生 Telegram 机器人命令未能通过 setMyCommands 成功注册,导致命令菜单从机器人界面中缺失。
🔍 症状
主要表现
Telegram 机器人正常接收和处理消息,但在网关启动时原生命令注册从未发生。
诊断输出模式
缺失的日志条目 bash
Search for setMyCommands in logs
grep -i “setMyCommands|setMyCommands|commands.native|BOT_COMMANDS” /var/log/openclaw/gateway.log
Expected: Multiple entries like:
[INFO] TelegramProvider: Registering native commands via setMyCommands
[INFO] TelegramProvider: Successfully registered 8 bot commands
[DEBUG] bot.api.setMyCommands called with
Actual: Zero matches
无自动完成菜单
在 Telegram 私信中输入 / 时,不显示命令菜单。斜杠命令自动补全功能需要在初始化期间调用 setMyCommands。
配置看起来正确 json { “channels”: { “telegram”: { “enabled”: true, “token”: “123456789:ABCdefGHI…”, “commands”: { “native”: true, “nativeSkills”: true } } } }
CLI 验证命令
bash
Check if commands are registered via Telegram API
curl -s “https://api.telegram.org/bot
Expected after successful registration:
{
“ok”: true,
“result”: [
{“command”: “help”, “description”: “Show available commands”},
{“command”: “status”, “description”: “Check system status”},
…
]
}
Actual (bug present):
{
“ok”: true,
“result”: []
}
静默失败特征
- 没有
ERROR或WARN级别的日志条目 - 网关启动成功完成(退出代码 0)
- Telegram 机器人正常响应消息
- 手动调用时技能命令正常执行
- 仅缺少命令菜单/自动补全功能
🧠 根因分析
架构背景
setMyCommands 注册发生在 Telegram provider 的初始化序列中。代码路径存在于 dist/bot-BwMz6R6-.js 中,但由于一个或多个早期返回条件而永远无法到达。
主要根因
1. 配置 Schema 不匹配
Telegram provider 将 commands.native 作为字符串值进行检查,但配置 schema 验证器会将 "true" 强制转换为布尔值 true,或将 "auto" 强制转换为意外的枚举值。条件检查静默失败:
javascript // In provider initialization (inferred from behavior) if (config.commands?.native !== ‘auto’ && config.commands?.native !== true) { return early; // Exits before setMyCommands is called }
// Problem: If config.commands.native is boolean true (not string ’true’) // or if the path is channels.telegram.commands.native vs nested structure // The comparison evaluates incorrectly
2. 异步初始化竞态条件
Telegram provider 可能在命令注册表填充之前初始化:
Gateway Start │ ├── Load Channels Config │ │ │ └── TelegramProvider.init() │ │ │ └── bot.api.setMyCommands(retryCommands) │ │ │ └── retryCommands = [] ← Commands not yet loaded │ └── Load Plugins/Skills │ └── Populate command registry
当在 provider 初始化时计算 retryCommands 时,技能命令列表为空,因为插件在 provider 初始化之后才加载。
3. Promise 链中的错误吞没
setMyCommands 调用包装在带有 .catch() 处理程序的 Promise 中,该处理程序吞没错误而不记录日志:
javascript // Inferred from symptom “no error, no warning” bot.api.setMyCommands(retryCommands) .then(() => logger.info(‘Commands registered’)) .catch(err => { // Error swallowed here - no logging // void err or empty catch block });
4. 功能标志覆盖
环境变量或功能标志可能全局禁用了命令注册:
bash
These environment variables would prevent registration
OPENCLAW_TELEGRAM_COMMANDS_ENABLED=false OPENCLAW_DISABLE_NATIVE_COMMANDS=1 TELEGRAM_SKIP_COMMAND_REGISTRATION=true
5. Provider 条件评估错误
Telegram provider 可能有一个评估错误的守卫条件:
javascript // Probable code path issue class TelegramProvider { async start() { // Bug: Checks wrong property path if (!this.config.channel?.commands?.native) { return this.startPolling(); // Skips command registration }
// This code is never reached
await this.registerCommands();
}
}
// Correct path should be: if (!this.config.commands?.native) { … }
故障序列图
┌─────────────────────────────────────────────────────────────┐ │ Gateway Startup │ ├─────────────────────────────────────────────────────────────┤ │ 1. Config.load() → Merges JSON + env vars │ │ └── channels.telegram.commands.native: true (boolean) │ │ │ │ 2. PluginRegistry.load() │ │ └── Skills loaded, command registry empty │ │ │ │ 3. TelegramProvider.init() │ │ └── Checks: config.commands?.native !== ‘auto’ │ │ └── Boolean true !== String ‘auto’ → exits early │ │ │ │ 4. setMyCommands() never called │ │ └── retryCommands: [] │ │ │ │ 5. Gateway ready, polling active │ │ └── Commands not registered, no errors logged │ └─────────────────────────────────────────────────────────────┘
环境特定触发因素
| 平台 | 触发器 | 机制 |
|---|---|---|
| macOS LaunchAgent | 顺序依赖 | Plist 按字母顺序加载服务 |
| Docker | 配置卷挂载 | 在环境变量覆盖应用之前解析 JSON |
| Linux systemd | 时序问题 | After=network.target 但不是 openclaw-ready.service |
| Windows Service | 注册表状态 | NSSM 在服务依赖项之前读取配置 |
🛠️ 逐步修复
修复策略 1:配置路径修正
最可能的问题是配置路径不正确或类型不匹配。OpenClaw 2026.4.14 期望特定的 schema 结构。
步骤 1:验证配置 Schema
bash
Check actual loaded configuration
cat ~/.openclaw/openclaw.json | jq ‘.channels.telegram.commands’
步骤 2:应用正确的配置
编辑您的 openclaw.json:
json // BEFORE (incorrect - may be wrong path or type) { “channels”: { “telegram”: { “commands”: { “native”: true } } } }
// AFTER (correct schema) { “channels”: { “telegram”: { “commands”: { “native”: “auto” } } } }
注意: 使用字符串 "auto" 而不是布尔值 true。代码与字符串字面量 'auto' 和 true(字符串)进行比较,而不是与布尔值 true 进行比较。
步骤 3:重启网关
bash
macOS LaunchAgent
launchctl unload ~/Library/LaunchAgents/ai.openclaw.gateway.plist launchctl load ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Linux systemd
sudo systemctl restart openclaw-gateway
Docker
docker restart openclaw-gateway
Direct (development)
pkill -f openclaw-gateway && openclaw gateway start
修复策略 2:手动命令注册(立即生效)
在调查启动问题的同时获得即时缓解:
步骤 1:识别所需命令
bash
List all registered commands from OpenClaw
grep -r “BOT_COMMANDS|registerCommand|command.*description”
~/.openclaw/node_modules/openclaw/dist/ 2>/dev/null
| head -30
步骤 2:通过 Telegram API 注册
bash
Replace with your bot token
curl -X POST “https://api.telegram.org/bot
-H “Content-Type: application/json”
-d ‘{
“commands”: [
{“command”: “help”, “description”: “Show available commands and usage”},
{“command”: “status”, “description”: “Display system status and health”},
{“command”: “new”, “description”: “Start a new conversation thread”},
{“command”: “reset”, “description”: “Reset conversation context”},
{“command”: “model”, “description”: “Show or change the active AI model”},
{“command”: “skills”, “description”: “List available skill plugins”}
],
“scope”: {“type”: “default”}
}’
步骤 3:验证注册
bash
curl -s “https://api.telegram.org/bot
预期输出: json { “ok”: true, “result”: [ {“command”: “help”, “description”: “Show available commands and usage”}, {“command”: “status”, “description”: “Display system status and health”} ] }
修复策略 3:环境变量覆盖
如果配置路径正确但 provider 仍然跳过注册:
步骤 1:设置调试环境变量
bash
Add to your shell profile or LaunchAgent plist EnvironmentVariables
export OPENCLAW_TELEGRAM_COMMANDS_DEBUG=1 export DEBUG=openclaw:telegram:commands
步骤 2:清除运行时缓存
bash rm -rf ~/.openclaw/cache/* rm -rf ~/.openclaw/runtime/state.json
步骤 3:使用详细日志重启
bash
Run with debug output
openclaw gateway start –log-level debug 2>&1 | grep -i “command|setMy”
修复策略 4:代码级热修复
如果您有修改运行时代码的权限:
步骤 1:定位 Provider 文件
bash
Find the Telegram provider
find ~/.openclaw/node_modules -name “provider-telegram*.js” -o
-name “TelegramProvider.js” 2>/dev/null
步骤 2:修补条件检查
找到早期返回条件并修复比较:
javascript // BEFORE (buggy) if (config.commands?.native !== ‘auto’ && config.commands?.native !== true) { return early; }
// AFTER (fixed) if (config.commands?.native === false || config.commands?.native === ‘false’) { return early; }
步骤 3:在 Catch 块中添加错误日志
javascript
// Find the setMyCommands call and add logging
try {
await bot.api.setMyCommands(retryCommands);
logger.info(TelegramProvider: Registered ${retryCommands.length} native commands);
} catch (err) {
logger.error(‘TelegramProvider: Failed to register commands’, { error: err.message });
// Don’t swallow - let it propagate
}
修复策略 5:Provider 启动顺序修复
如果问题是与插件加载的竞态条件:
步骤 1:添加启动依赖
对于 LaunchAgent (ai.openclaw.gateway.plist):
xml
对于 systemd (openclaw-gateway.service):
ini
[Unit]
After=network.target
After=time-sync.target
Wants=time-sync.target
[Service] ExecStartPre=/bin/sleep 3 Restart=on-failure RestartSec=5
🧪 验证
立即验证步骤
步骤 1:检查网关日志中的命令注册
bash
Tail logs with command registration filter
tail -f /var/log/openclaw/gateway.log 2>/dev/null | grep -E “setMyCommands|commands.*registered|native.*command”
Or for recent startup
grep -E “setMyCommands|commands.*registered|native.*command”
/var/log/openclaw/gateway.log | tail -20
预期输出:
[TIMESTAMP] INFO TelegramProvider: Initializing native command registration [TIMESTAMP] INFO TelegramProvider: Built-in commands loaded: help, status, new, reset, model [TIMESTAMP] INFO TelegramProvider: Skill commands loaded: 4 commands [TIMESTAMP] INFO TelegramProvider: Calling setMyCommands with 8 commands [TIMESTAMP] INFO TelegramProvider: Successfully registered 8 bot commands via setMyCommands
实际输出(bug 仍存在):
No matching entries found
步骤 2:通过 Telegram API 验证
bash
Replace with your bot token
TELEGRAM_TOKEN=“123456789:ABCdefGHI…”
curl -s “https://api.telegram.org/bot${TELEGRAM_TOKEN}/getMyCommands" | jq .
预期: json { “ok”: true, “result”: [ { “command”: “help”, “description”: “Show available commands” }, { “command”: “status”, “description”: “Display system status” } ] }
实际(未修复): json { “ok”: true, “result”: [] }
步骤 3:在 Telegram 中测试命令菜单
- 打开与 Telegram 机器人的私信
- 输入
/— 命令菜单应出现并带有自动补全 - 尝试每个命令:
/help、/status、/new、/reset
预期: 输入 / 时立即出现命令菜单
实际(未修复): 不显示菜单;必须手动输入命令
自动化验证脚本
bash #!/bin/bash
verify-telegram-commands.sh
TELEGRAM_TOKEN="${OPENCLAW_TELEGRAM_TOKEN:-}”
if [ -z “$TELEGRAM_TOKEN” ]; then echo “ERROR: OPENCLAW_TELEGRAM_TOKEN not set” exit 1 fi
echo “=== Telegram Bot Commands Verification ===” echo ""
Check registered commands
RESPONSE=$(curl -s “https://api.telegram.org/bot${TELEGRAM_TOKEN}/getMyCommands") COUNT=$(echo “$RESPONSE” | jq ‘.result | length’)
echo “Registered commands: $COUNT” echo “$RESPONSE” | jq -r ‘.result[] | " /” + .command + " - " + .description’
if [ “$COUNT” -gt 0 ]; then echo "" echo “✓ SUCCESS: Commands are registered” exit 0 else echo "" echo “✗ FAILURE: No commands registered” exit 1 fi
运行验证: bash chmod +x verify-telegram-commands.sh ./verify-telegram-commands.sh
预期输出:
=== Telegram Bot Commands Verification ===
Registered commands: 6 /help - Show available commands /status - Display system status /new - Start a new conversation /reset - Reset conversation context /model - Show or change AI model /skills - List skill plugins
✓ SUCCESS: Commands are registered
日志分析清单
应用修复后,验证这些日志条目在启动时出现:
| 日志条目 | 状态 | 含义 |
|---|---|---|
TelegramProvider: Initializing native command registration | ✓ 必需 | Provider 检测到原生命令已启用 |
TelegramProvider: Built-in commands loaded | ✓ 必需 | 核心命令已枚举 |
TelegramProvider: Skill commands loaded: N commands | ✓ 如果 nativeSkills 启用 | 插件命令已加载 |
TelegramProvider: Calling setMyCommands with N commands | ✓ 必需 | API 调用已启动 |
TelegramProvider: Successfully registered N bot commands | ✓ 必需 | API 调用成功 |
⚠️ 常见陷阱
配置陷阱
1. 类型强制转换不匹配
json // INCORRECT - boolean instead of string “native”: true
// CORRECT - string value “native”: “auto”
Provider 代码可能与字符串字面量进行比较。在 JavaScript 中,布尔值 true 永远不会等于字符串 "true"。
2. 嵌套路径错误
json // INCORRECT - wrong nesting “telegram”: { “plugin”: { “commands”: { “native”: true } } }
// CORRECT - expected path “telegram”: { “commands”: { “native”: “auto” } }
3. 环境变量覆盖被忽略
bash
Set in shell but not passed to LaunchAgent
export OPENCLAW_TELEGRAM_COMMANDS_ENABLED=true # Ignored by LaunchAgent
Correct: Add to plist EnvironmentVariables
平台特定陷阱
macOS LaunchAgent
| 陷阱 | 症状 | 解决方案 |
|---|---|---|
| Config cached by launchd | Changes don’t take effect | 运行 launchctl unload/load 循环 |
| User-level vs system plist | Permission denied | 检查 ~/Library/LaunchAgents/ vs /Library/LaunchAgents/ |
| Stale PID preventing restart | “Already running” | launchctl remove ai.openclaw.gateway && launchctl load |
Docker Container
| 陷阱 | 症状 | 解决方案 |
|---|---|---|
| Volume mount order | Config not found | 在应用卷之前挂载配置卷 |
| ENV var timing | Overrides not applied | 使用 docker-compose.override.yml |
| Network isolation | API calls fail | 确保容器可以访问 api.telegram.org |
Linux Systemd
| 陷阱 | 症状 | 解决方案 |
|---|---|---|
| Service starts too early | Race condition | 添加 ExecStartPre=/bin/sleep 5 |
| Journal truncation | Logs missing | journalctl -u openclaw-gateway -n 1000 |
| SELinux/AppArmor | Network blocked | setsebool -P nis_enabled 1 |
运行时陷阱
1. Token 不匹配
如果 openclaw.json 中使用的机器人 token 与环境变量中的 token 不同,getMyCommands 和 setMyCommands 将引用不同的机器人。
bash
Verify token consistency
jq ‘.channels.telegram.token’ ~/.openclaw/openclaw.json echo $OPENCLAW_TELEGRAM_TOKEN
2. BotFather 命令范围
Telegram 机器人可以在不同的范围内注册命令:
default- 所有聊天commands_in_private- 仅私人聊天- 带
chat_id的每聊范围
如果之前通过 BotFather 使用某个范围设置了命令,setMyCommands 可能无法覆盖它们。
bash
Clear all command scopes
curl -X POST “https://api.telegram.org/bot
-H “Content-Type: application/json”
-d ‘{“scope”: {“type”: “all_private_chats”}}’
curl -X POST “https://api.telegram.org/bot
-H “Content-Type: application/json”
-d ‘{}’ # Delete default scope too
3. 速率限制
Telegram 对 setMyCommands 的速率限制约为每秒 1 次调用。如果在调试期间网关快速重启,API 可能会拒绝调用。
bash
Check for rate limit errors
grep -i “Too Many Requests|retry_after” /var/log/openclaw/gateway.log
4. 机器人模式限制
某些模式(如 inline-only、受限)的机器人无法使用 setMyCommands。
开发陷阱
热重载未重载 Provider
某些热重载实现会重新初始化插件但不重新初始化 Telegram provider。命令永远不会被重新注册。
bash
Full restart required, not just config reload
pkill -f openclaw openclaw gateway start
调试日志使错误静默
较高的 logLevel 设置(debug、trace)有时会导致错误被记录在被过滤掉的级别。
bash
Explicitly enable all Telegram-related logs
openclaw gateway start –log-level debug –log-filter “telegram,commands,provider”
🔗 相关错误
直接相关错误
| 错误代码 | 描述 | 关联 |
|---|---|---|
BOT_COMMANDS_TOO_MUCH | 超过 100 个命令时的 Telegram API 错误 | 注册过多技能时 setMyCommands 失败 |
TELEGRAM_API_ERROR_400 | Telegram API 错误请求 | 向 setMyCommands 发送格式错误的命令负载 |
TELEGRAM_API_ERROR_401 | 未授权 | 无效的机器人 token 导致 setMyCommands 失败 |
TELEGRAM_API_ERROR_429 | 请求过多 | setMyCommands 调用的速率限制 |
历史相关问题
| 问题 | 描述 | 可能性 |
|---|---|---|
lossless-claw 上下文引擎错误 | 重启期间的 LCM 错误(问题中已注明) | 次要问题,独立解决 |
| 插件初始化时序 | 技能在 provider 初始化之后加载 | v2026.x 中出现的竞态条件模式 |
| 版本之间的配置 schema 变更 | 破坏性配置格式变更 | 版本发布中的常见问题 |
| Provider 生命周期变更 | v2026.4 中 Telegram provider 重构 | 代码路径 bug 的直接原因 |
其他渠道的类似症状
| 渠道 | 相关症状 | 区分特征 |
|---|---|---|
| Discord | 斜杠命令未注册 | 不同的 API(/applications 端点) |
| Slack | App home 命令缺失 | 使用 apps.connections.install 流程 |
| Matrix | 命令前缀不显示 | 使用房间状态事件代替 |
外部参考
- Telegram Bot API: setMyCommands —
https://core.telegram.org/bots/api#setmycommands - Telegram Bot API: getMyCommands —
https://core.telegram.org/bots/api#getmycommands - grammY Commands Plugin —
https://grammy.dev/plugins/commands - OpenClaw Config Schema —
~/.openclaw/node_modules/openclaw/schema/config.json
相关日志模式
在诊断类似问题时,在网关日志中搜索这些模式:
bash
All Telegram-related logging
grep -E “TelegramProvider|Telegram.*provider|telegram” /var/log/openclaw/gateway.log
Command registration attempts
grep -E “setMyCommands|register.*command|command.*registration” /var/log/openclaw/gateway.log
API errors
grep -E “api.*error|api.*fail|telegram.*error” /var/log/openclaw/gateway.log
Configuration loading
grep -E “config.*load|channels.*init|provider.*start” /var/log/openclaw/gateway.log