Summary
When channels.telegram.webhookUrl is configured, OpenClaw continues running its long-polling transport in the background. This polling transport periodically calls getUpdates, which causes Telegram to silently delete the registered webhook. The result is a continuous wipe cycle: webhook is set on startup → polling transport issues getUpdates ~30s later → Telegram interprets this as "switch to polling mode" and clears the webhook → inbound messages are lost until the webhook is manually re-registered.
Version
OpenClaw 2026.6.1 (confirmed via openclaw --version)
Steps to reproduce
- Configure
channels.telegram.webhookUrl + channels.telegram.webhookSecret in openclaw.json
- Start or restart the gateway
- Observe via
getWebhookInfo: webhook URL is set immediately after startup
- Wait 20–35 seconds
- Observe via
getWebhookInfo: webhook URL is now empty — cleared by Telegram
- Repeat step 4–5: it wipes every ~30 seconds continuously as long as the gateway runs
Root cause
The long-polling watchdog (pollingStallThresholdMs) runs even when webhookUrl is configured — OpenClaw has no pure-webhook mode. The polling transport calls getUpdates on its liveness cycle; per Telegram Bot API specification, calling getUpdates while a webhook is active automatically deletes the webhook (this is documented Telegram behaviour, not a Telegram bug).
From the OpenClaw docs (channels/telegram.md):
"Long polling is the default mode; webhook mode is optional."
"A still-active webhook surfaces as a getUpdates conflict; OpenClaw then rebuilds the Telegram transport and retries webhook cleanup."
This confirms the polling path always runs. The pollingStallThresholdMs config key (range 30000–600000) only tunes the watchdog timing — it does not disable polling.
The complete channels.telegram schema was enumerated via openclaw config schema lookup channels.telegram. There is no disablePolling, mode: "webhook", webhookOnly, transport, or any flag to stop the poller when in webhook mode.
Impact
- Inbound Telegram DMs and group messages silently dropped for ~30s windows every minute
- Every gateway restart resets the webhook → DM blackout until manually re-registered
- Even with
webhookUrl configured, the bot receives no messages unless an external process continuously re-asserts setWebhook
Current workaround
A systemd timer fires every 15s, calls setWebhook via getWebhookInfo check (never getUpdates), and re-asserts the webhook before the next polling wipe. This works but is a band-aid.
# /etc/systemd/system/tg-webhook-guard.timer
[Timer]
OnBootSec=20s
OnUnitActiveSec=15s
AccuracySec=1s
Requested fix
Add a disablePolling: true or transport: "webhook" config flag to channels.telegram that:
- Skips starting the long-polling transport entirely when
webhookUrl is set
- Does NOT call
getUpdates or deleteWebhook during normal operation
- Only uses the webhook listener path for inbound messages
Alternatively, make webhook mode the automatic behaviour when webhookUrl is configured (breaking change, but semantically correct).
Evidence
Gateway log shows liveness warning: eventLoopDelayP99Ms=4099 alongside continuous polling transport restarts. Empirical test: set webhook, poll getWebhookInfo every 10s with no guard running:
T+0s → set
T+10s → https://example.com/telegram-webhook ✅
T+20s → https://example.com/telegram-webhook ✅
T+30s → (empty) ❌ ← wiped by getUpdates
T+40s → (empty)
Reproduced across 3 independent gateway restarts on OpenClaw 2026.6.1.
Summary
When
channels.telegram.webhookUrlis configured, OpenClaw continues running its long-polling transport in the background. This polling transport periodically callsgetUpdates, which causes Telegram to silently delete the registered webhook. The result is a continuous wipe cycle: webhook is set on startup → polling transport issuesgetUpdates~30s later → Telegram interprets this as "switch to polling mode" and clears the webhook → inbound messages are lost until the webhook is manually re-registered.Version
OpenClaw 2026.6.1 (confirmed via
openclaw --version)Steps to reproduce
channels.telegram.webhookUrl+channels.telegram.webhookSecretinopenclaw.jsongetWebhookInfo: webhook URL is set immediately after startupgetWebhookInfo: webhook URL is now empty — cleared by TelegramRoot cause
The long-polling watchdog (
pollingStallThresholdMs) runs even whenwebhookUrlis configured — OpenClaw has no pure-webhook mode. The polling transport callsgetUpdateson its liveness cycle; per Telegram Bot API specification, callinggetUpdateswhile a webhook is active automatically deletes the webhook (this is documented Telegram behaviour, not a Telegram bug).From the OpenClaw docs (
channels/telegram.md):This confirms the polling path always runs. The
pollingStallThresholdMsconfig key (range30000–600000) only tunes the watchdog timing — it does not disable polling.The complete
channels.telegramschema was enumerated viaopenclaw config schema lookup channels.telegram. There is nodisablePolling,mode: "webhook",webhookOnly,transport, or any flag to stop the poller when in webhook mode.Impact
webhookUrlconfigured, the bot receives no messages unless an external process continuously re-assertssetWebhookCurrent workaround
A systemd timer fires every 15s, calls
setWebhookviagetWebhookInfocheck (nevergetUpdates), and re-asserts the webhook before the next polling wipe. This works but is a band-aid.# /etc/systemd/system/tg-webhook-guard.timer [Timer] OnBootSec=20s OnUnitActiveSec=15s AccuracySec=1sRequested fix
Add a
disablePolling: trueortransport: "webhook"config flag tochannels.telegramthat:webhookUrlis setgetUpdatesordeleteWebhookduring normal operationAlternatively, make webhook mode the automatic behaviour when
webhookUrlis configured (breaking change, but semantically correct).Evidence
Gateway log shows
liveness warning: eventLoopDelayP99Ms=4099alongside continuous polling transport restarts. Empirical test: set webhook, pollgetWebhookInfoevery 10s with no guard running:Reproduced across 3 independent gateway restarts on OpenClaw 2026.6.1.