openclaw - ✅(Solved) Fix [Bug]: Telegram polling leases leak across in-process gateway restarts [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#81507Fetched 2026-05-14 03:31:23
View on GitHub
Comments
1
Participants
2
Timeline
8
Reactions
2
Timeline (top)
labeled ×2mentioned ×2subscribed ×2commented ×1

Telegram polling lease registry leaks stale entries across in-process gateway restarts, causing all bot accounts to fail with "duplicate poller" errors indefinitely (855+ errors/day).

Root Cause

Root cause is in extensions/telegram/src/polling-lease.ts — the lease registry is stored on a process-level Map keyed by Symbol.for("openclaw.telegram.pollingLeases"), which is never cleared during the Telegram channel provider's shutdown/teardown. An in-process restart recycles the gateway lifecycle but the Node.js process lives on, so zombie lease entries persist and block acquireTelegramPollingLease().

Fix Action

Fixed

PR fix notes

PR #81533: fix(telegram): release polling leases at in-process gateway restart boundary

Description (problem / solution / changelog)

Fixes #81507

Root cause

Telegram polling leases live on a process-global Symbol.for("openclaw.telegram.pollingLeases") Map. The registry survives any gateway restart that recycles the lifecycle without exiting the Node process (SIGUSR1 in-process restart, OPENCLAW_NO_RESPAWN reload, etc.).

When the previous lifecycle's monitorTelegramProvider task is dropped before its finally pollingLease.release() runs, the entry stays. The next lifecycle then calls acquireTelegramPollingLease(), finds a same-token entry whose abort signal hasn't observed an abort yet, and throws the duplicate-poller error indefinitely. This matches the reporter's "855 errors/day" symptom.

Fix

Lifecycle-owned cleanup at the in-process restart boundary, per Codex review.

  1. New src/infra/in-process-restart-hooks.ts — small process-global registry of synchronous, idempotent reset hooks. Hooks are best-effort (errors swallowed) and the registry is stored on a Symbol.for(...) key so it deduplicates across module reloads.
  2. New openclaw/plugin-sdk/lifecycle-restart-hooks re-export so plugins can register without importing internal infra.
  3. extensions/telegram/src/polling-lease.ts — exports releaseTelegramPollingLeasesForLifecycleReset() and self-registers it on first module load (process-symbol-guarded so duplicate ESM loads don't double-register).
  4. src/cli/gateway-cli/run-loop.ts — invokes runInProcessRestartHooks() from the existing restart iteration hook, alongside resetAllLanes() / resetGatewayRestartStateForInProcessRestart() / reloadTaskRegistryFromStore().

The cleanup is only invoked at the in-process restart boundary. Steady-state acquireTelegramPollingLease() still rejects two live pollers for the same bot token within one lifecycle. Late release() calls from dropped previous-lifecycle tasks are safe — release() is owner-checked and idempotent, so they won't delete a fresh lease that the new lifecycle just acquired.

Tests

  • extensions/telegram/src/polling-lease.test.ts — three new regressions:
    • stale same-token leases get cleared at the restart boundary, fresh acquire succeeds, and a late stale release() does NOT delete the fresh lease;
    • two concurrent live pollers within one lifecycle still rejected (same-token guard preserved);
    • the cleanup is wired into the shared in-process restart hook registry (no Telegram-specific knowledge needed at the call site).
  • src/cli/gateway-cli/run-loop.test.ts — adds runInProcessRestartHooks mock + assertion that it's called once per restart iteration alongside the existing lane/registry resets.

Verification

  • pnpm test extensions/telegram/src/polling-lease.test.ts
  • pnpm test src/cli/gateway-cli/run-loop.test.ts

(Local pnpm not available — relying on CI for the full run.)

Changed files

  • extensions/telegram/src/polling-lease.test.ts (modified, +89/-0)
  • extensions/telegram/src/polling-lease.ts (modified, +64/-0)
  • package.json (modified, +4/-0)
  • src/cli/gateway-cli/lifecycle.runtime.ts (modified, +1/-0)
  • src/cli/gateway-cli/run-loop.test.ts (modified, +7/-0)
  • src/cli/gateway-cli/run-loop.ts (modified, +5/-0)
  • src/infra/in-process-restart-hooks.ts (added, +84/-0)
  • src/plugin-sdk/lifecycle-restart-hooks.ts (added, +10/-0)

Code Example

Telegram polling already active for bot token <fingerprint> on account "<name>" 
(XXXXs old); refusing duplicate poller for account "<name>".

---

Telegram polling already active for bot token <fingerprint> on account "<name>" 
(XXXXs old); refusing duplicate poller for account "<name>".
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

Telegram polling lease registry leaks stale entries across in-process gateway restarts, causing all bot accounts to fail with "duplicate poller" errors indefinitely (855+ errors/day).

Steps to reproduce

  1. Configure multiple Telegram bot accounts in OpenClaw (each with a distinct bot token)
  2. Trigger an in-process gateway restart (e.g., via config change, SIGHUP, or /restart in OPENCLAW_NO_RESPAWN mode)
  3. Check logs immediately after restart

Expected behavior

Gateway restart should tear down old polling sessions cleanly. New polling cycles should start without interference from the previous lifecycle.

Actual behavior

Every Telegram account fails with:

Telegram polling already active for bot token <fingerprint> on account "<name>" 
(XXXXs old); refusing duplicate poller for account "<name>".

OpenClaw version

2026.5.7

Operating system

Linux x64 (Fedora 43)

Install method

curl -fsSL https://openclaw.ai/install.sh | bash

Model

N/A — infrastructure bug, not model-specific.

Provider / routing chain

N/A — bug is in the Telegram channel polling lease subsystem.

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Telegram polling already active for bot token <fingerprint> on account "<name>" 
(XXXXs old); refusing duplicate poller for account "<name>".

Impact and severity

High noise, no user-visible breakage if the pre-restart pollers are still alive. If the old pollers have died and the stale leases block new ones, messages are silently dropped. In this case, ~855 errors logged across 5 agents over ~5 hours, filling logs with useless noise.

Additional information

Root cause is in extensions/telegram/src/polling-lease.ts — the lease registry is stored on a process-level Map keyed by Symbol.for("openclaw.telegram.pollingLeases"), which is never cleared during the Telegram channel provider's shutdown/teardown. An in-process restart recycles the gateway lifecycle but the Node.js process lives on, so zombie lease entries persist and block acquireTelegramPollingLease().

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Gateway restart should tear down old polling sessions cleanly. New polling cycles should start without interference from the previous lifecycle.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: Telegram polling leases leak across in-process gateway restarts [1 pull requests, 1 comments, 2 participants]