Telegram: commands.native Not Registering setMyCommands at Startup
Native Telegram bot commands fail to register via setMyCommands despite correct configuration in OpenClaw 2026.4.14, leaving command menus absent from the bot interface.
๐ Symptoms
Primary Manifestations
The Telegram bot accepts and processes messages normally, but native command registration never occurs at gateway startup.
Diagnostic Output Patterns
Missing Log Entries 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
No Autocomplete Menu
When typing / in a Telegram DM with the bot, no command menu appears. The slash-command autocomplete feature requires setMyCommands to have been called during initialization.
Configuration Appears Correct json { “channels”: { “telegram”: { “enabled”: true, “token”: “123456789:ABCdefGHI…”, “commands”: { “native”: true, “nativeSkills”: true } } } }
CLI Verification Commands
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”: []
}
Silent Failure Characteristics
- No
ERRORorWARNlevel log entries - Gateway startup completes successfully (exit code 0)
- Telegram bot responds to messages normally
- Skill commands execute correctly when called manually
- Only the command menu/autocomplete is missing
๐ง Root Cause
Architectural Context
The setMyCommands registration occurs in the Telegram provider’s initialization sequence. The code path exists in dist/bot-BwMz6R6-.js but is never reached due to one or more early-return conditions.
Primary Root Causes
1. Configuration Schema Mismatch
The Telegram provider checks commands.native as a string value, but the configuration schema validator coerces "true" to boolean true or "auto" to an unexpected enum. The conditional check fails silently:
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. Async Initialization Race Condition
The Telegram provider may initialize before the command registry is populated:
Gateway Start โ โโโ Load Channels Config โ โ โ โโโ TelegramProvider.init() โ โ โ โโโ bot.api.setMyCommands(retryCommands) โ โ โ โโโ retryCommands = [] โ Commands not yet loaded โ โโโ Load Plugins/Skills โ โโโ Populate command registry
When retryCommands is evaluated at provider init time, the skill command list is empty because plugins load after the provider initializes.
3. Error Swallowing in Promise Chain
The setMyCommands call is wrapped in a Promise with a .catch() handler that swallows errors without logging:
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. Feature Flag Override
An environment variable or feature flag may be disabling command registration globally:
bash
These environment variables would prevent registration
OPENCLAW_TELEGRAM_COMMANDS_ENABLED=false OPENCLAW_DISABLE_NATIVE_COMMANDS=1 TELEGRAM_SKIP_COMMAND_REGISTRATION=true
5. Provider Condition Evaluation Bug
The Telegram provider may have a guard condition that evaluates incorrectly:
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) { … }
Failure Sequence Diagram
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ 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 โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Environment-Specific Triggers
| Platform | Trigger | Mechanism |
|---|---|---|
| macOS LaunchAgent | Order dependency | Plist loads services in alphabetical order |
| Docker | Config volume mount | JSON parsed before env overrides applied |
| Linux systemd | Timing | After=network.target but not openclaw-ready.service |
| Windows Service | Registry state | NSSM reads config before service dependencies |
๐ ๏ธ Step-by-Step Fix
Fix Strategy 1: Configuration Path Correction
The most likely issue is an incorrect configuration path or type mismatch. OpenClaw 2026.4.14 expects a specific schema structure.
Step 1: Verify Configuration Schema
bash
Check actual loaded configuration
cat ~/.openclaw/openclaw.json | jq ‘.channels.telegram.commands’
Step 2: Apply Correct Configuration
Edit your openclaw.json:
json // BEFORE (incorrect - may be wrong path or type) { “channels”: { “telegram”: { “commands”: { “native”: true } } } }
// AFTER (correct schema) { “channels”: { “telegram”: { “commands”: { “native”: “auto” } } } }
Note: Use the string "auto" instead of boolean true. The code compares against string literals 'auto' and true (string), not boolean true.
Step 3: Restart Gateway
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
Fix Strategy 2: Manual Command Registration (Immediate)
For immediate relief while investigating the startup issue:
Step 1: Identify Required Commands
bash
List all registered commands from OpenClaw
grep -r “BOT_COMMANDS|registerCommand|command.*description”
~/.openclaw/node_modules/openclaw/dist/ 2>/dev/null
| head -30
Step 2: Register via 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”}
}’
Step 3: Verify Registration
bash
curl -s “https://api.telegram.org/bot
Expected output: json { “ok”: true, “result”: [ {“command”: “help”, “description”: “Show available commands and usage”}, {“command”: “status”, “description”: “Display system status and health”} ] }
Fix Strategy 3: Environment Variable Override
If the configuration path is correct but the provider still skips registration:
Step 1: Set Debug Environment Variable
bash
Add to your shell profile or LaunchAgent plist EnvironmentVariables
export OPENCLAW_TELEGRAM_COMMANDS_DEBUG=1 export DEBUG=openclaw:telegram:commands
Step 2: Clear Runtime Cache
bash rm -rf ~/.openclaw/cache/* rm -rf ~/.openclaw/runtime/state.json
Step 3: Restart with Verbose Logging
bash
Run with debug output
openclaw gateway start –log-level debug 2>&1 | grep -i “command|setMy”
Fix Strategy 4: Code-Level Hotfix
If you have access to modify the runtime code:
Step 1: Locate the Provider File
bash
Find the Telegram provider
find ~/.openclaw/node_modules -name “provider-telegram*.js” -o
-name “TelegramProvider.js” 2>/dev/null
Step 2: Patch the Conditional Check
Locate the early-return condition and fix the comparison:
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; }
Step 3: Add Error Logging to Catch Block
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
}
Fix Strategy 5: Provider Start Order Fix
If the issue is a race condition with plugin loading:
Step 1: Add Startup Dependency
For LaunchAgent (ai.openclaw.gateway.plist):
xml
For 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
๐งช Verification
Immediate Verification Steps
Step 1: Check Gateway Logs for Command Registration
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
Expected output:
[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
Actual output (bug still present):
No matching entries found
Step 2: Verify via Telegram API
bash
Replace with your bot token
TELEGRAM_TOKEN=“123456789:ABCdefGHI…”
curl -s “https://api.telegram.org/bot${TELEGRAM_TOKEN}/getMyCommands" | jq .
Expected: json { “ok”: true, “result”: [ { “command”: “help”, “description”: “Show available commands” }, { “command”: “status”, “description”: “Display system status” } ] }
Actual (unfixed): json { “ok”: true, “result”: [] }
Step 3: Test Command Menu in Telegram
- Open a DM with your Telegram bot
- Type
/โ the command menu should appear with autocomplete - Try each command:
/help,/status,/new,/reset
Expected: Command menu appears immediately when typing /
Actual (unfixed): No menu appears; commands must be typed manually
Automated Verification Script
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
Run the verification: bash chmod +x verify-telegram-commands.sh ./verify-telegram-commands.sh
Expected output:
=== 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
Log Analysis Checklist
After applying fixes, verify these log entries appear at startup:
| Log Entry | Status | Meaning |
|---|---|---|
TelegramProvider: Initializing native command registration | โ Required | Provider detected native commands enabled |
TelegramProvider: Built-in commands loaded | โ Required | Core commands enumerated |
TelegramProvider: Skill commands loaded: N commands | โ If nativeSkills enabled | Plugin commands loaded |
TelegramProvider: Calling setMyCommands with N commands | โ Required | API call initiated |
TelegramProvider: Successfully registered N bot commands | โ Required | API call succeeded |
โ ๏ธ Common Pitfalls
Configuration Pitfalls
1. Type Coercion Mismatch
json // INCORRECT - boolean instead of string “native”: true
// CORRECT - string value “native”: “auto”
The provider code likely compares against string literals. Boolean true will never equal the string "true" in JavaScript.
2. Nested Path Errors
json // INCORRECT - wrong nesting “telegram”: { “plugin”: { “commands”: { “native”: true } } }
// CORRECT - expected path “telegram”: { “commands”: { “native”: “auto” } }
3. Environment Variable Override Ignored
bash
Set in shell but not passed to LaunchAgent
export OPENCLAW_TELEGRAM_COMMANDS_ENABLED=true # Ignored by LaunchAgent
Correct: Add to plist EnvironmentVariables
Platform-Specific Traps
macOS LaunchAgent
| Pitfall | Symptom | Solution |
|---|---|---|
| Config cached by launchd | Changes don’t take effect | Run launchctl unload/load cycle |
| User-level vs system plist | Permission denied | Check ~/Library/LaunchAgents/ vs /Library/LaunchAgents/ |
| Stale PID preventing restart | “Already running” | launchctl remove ai.openclaw.gateway && launchctl load |
Docker Container
| Pitfall | Symptom | Solution |
|---|---|---|
| Volume mount order | Config not found | Mount config volume before application volume |
| ENV var timing | Overrides not applied | Use docker-compose.override.yml |
| Network isolation | API calls fail | Ensure container can reach api.telegram.org |
Linux Systemd
| Pitfall | Symptom | Solution |
|---|---|---|
| Service starts too early | Race condition | Add ExecStartPre=/bin/sleep 5 |
| Journal truncation | Logs missing | journalctl -u openclaw-gateway -n 1000 |
| SELinux/AppArmor | Network blocked | setsebool -P nis_enabled 1 |
Runtime Pitfalls
1. Token Mismatch
If the bot token used in openclaw.json differs from the token in environment variables, getMyCommands and setMyCommands will reference different bots.
bash
Verify token consistency
jq ‘.channels.telegram.token’ ~/.openclaw/openclaw.json echo $OPENCLAW_TELEGRAM_TOKEN
2. BotFather Command Scope
Telegram bots can have commands registered at different scopes:
default- All chatscommands_in_private- Only private chats- Per-chat scope with
chat_id
If commands were previously set with a scope via BotFather, setMyCommands may not override them.
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. Rate Limiting
Telegram rate limits setMyCommands to approximately 1 call per second. If the gateway restarts rapidly during debugging, the API may reject calls.
bash
Check for rate limit errors
grep -i “Too Many Requests|retry_after” /var/log/openclaw/gateway.log
4. Bot Mode Restrictions
Bots in certain modes (e.g.,_inline-only, restricted) cannot use setMyCommands.
Development Pitfalls
Hot Reload Misses Provider
Some hot-reload implementations reinitialize plugins but not the Telegram provider. Commands are never re-registered.
bash
Full restart required, not just config reload
pkill -f openclaw openclaw gateway start
Debug Logging Silences Errors
High logLevel settings (debug, trace) can sometimes cause errors to be logged at a level that’s filtered out.
bash
Explicitly enable all Telegram-related logs
openclaw gateway start –log-level debug –log-filter “telegram,commands,provider”
๐ Related Errors
Directly Related Errors
| Error Code | Description | Connection |
|---|---|---|
BOT_COMMANDS_TOO_MUCH | Telegram API error when exceeding 100 commands | setMyCommands fails when registering too many skills |
TELEGRAM_API_ERROR_400 | Bad request to Telegram API | Malformed command payload to setMyCommands |
TELEGRAM_API_ERROR_401 | Unauthorized | Invalid bot token prevents setMyCommands |
TELEGRAM_API_ERROR_429 | Too many requests | Rate limiting on setMyCommands calls |
Historically Related Issues
| Issue | Description | Likelihood |
|---|---|---|
lossless-claw context engine errors | LCM errors during restart (noted in issue) | Secondary issue, resolved independently |
| Plugin initialization timing | Skills load after provider init | Race condition pattern seen in v2026.x |
| Config schema changes between versions | Breaking config format changes | Common in milestone releases |
| Provider lifecycle changes | Telegram provider refactor in v2026.4 | Direct cause of code path bug |
Similar Symptoms in Other Channels
| Channel | Related Symptom | Differentiator |
|---|---|---|
| Discord | Slash commands not registering | Different API (/applications endpoint) |
| Slack | App home commands missing | Uses apps.connections.install flow |
| Matrix | Command prefixes not showing | Uses room state events instead |
External References
- 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
Related Log Patterns
Search for these patterns in gateway logs when diagnosing similar issues:
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