#6447: fix(telegram): auto-restart polling when grammY runner exits silently
channel: telegram
## Summary
- When `getUpdates` times out (500s) and grammY's `maxRetryTime` is exhausted with `silent:true`, the runner resolves `task()` instead of rejecting — causing the polling loop to exit cleanly and leave the Telegram channel dead indefinitely
- The polling loop now detects this (abort signal exists but hasn't fired) and restarts with exponential backoff (2s initial, 30s max)
- Added `"timed out"` to recoverable message snippets so the catch path also handles timeout errors in non-silent mode
## Test plan
- [x] `src/telegram/monitor.test.ts` — all 5 tests pass
- [x] `src/telegram/network-errors.test.ts` — all 7 tests pass
- [ ] Deploy and verify Telegram channel recovers automatically after a `getUpdates` timeout
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates the Telegram polling monitor to handle a grammY runner edge case where `runner.task()` can resolve silently (not reject) after `maxRetryTime` is exhausted with `silent: true`. The loop now treats a resolved task as “unexpected stop” when an `abortSignal` exists but hasn’t fired, and restarts polling with exponential backoff. It also expands recoverable Telegram network error detection by adding the "timed out" message snippet so timeout errors are treated as retryable.
Main area touched is `src/telegram/monitor.ts`, which owns the long-running polling loop for Telegram providers. `src/telegram/network-errors.ts` provides shared error classification used by polling/webhook/send contexts.
<h3>Confidence Score: 3/5</h3>
- This PR is likely safe to merge but has a couple edge cases around lifecycle/restart behavior worth tightening.
- The change is small and localized, and the restart/backoff logic matches the described failure mode. Main concerns are around abort listener management inside a restart loop and the fact that silent runner exits still cause a full return when no abort signal is provided, which could reintroduce a dead Telegram poller depending on how this function is invoked.
- src/telegram/monitor.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#6463: fix(telegram): improve timeout handling and prevent channel exits
by ai-fanatic · 2026-02-01
88.0%
#7247: fix(telegram): abort stale getUpdates connections after long-poll t...
by JanderV · 2026-02-02
85.7%
#10850: fix(telegram): await runner.stop() to prevent polling race conditio...
by talhaorak · 2026-02-07
85.7%
#11688: feat(telegram): add health check watchdog for long-polling
by rmfalco89 · 2026-02-08
82.8%
#8166: fix(telegram): lifecycle fixes for duplicate messages and auto-reco...
by cheenu1092-oss · 2026-02-03
82.8%
#5561: fix(telegram): auto-restart on timeout + lower API timeout to 60s
by jesseproudman · 2026-01-31
82.5%
#7141: fix(telegram): unify network error detection to prevent poll crashes
by hclsys · 2026-02-02
81.4%
#3186: fix(telegram): sanitize update offset + lock polling
by daxiong888 · 2026-01-28
80.9%
#12870: fix: recover from telegram fetch errors (issue #12835)
by ambicuity · 2026-02-09
79.1%
#11340: Telegram: skip empty message text instead of throwing (#11238)
by lailoo · 2026-02-07
77.6%