Telegram plugin: zombie bun processes consume 100% CPU after session close
Resolved 💬 7 comments Opened Apr 3, 2026 by yulonh Closed May 28, 2026
Bug
When a Claude Code session ends without cleanly closing stdin (e.g. force quit, crash, or the stdin pipe not being torn down properly), the Telegram plugin's bun server.ts process becomes orphaned (PPID becomes 1) and enters an infinite 409-retry loop in bot.start(), consuming 100% CPU permanently. Multiple sessions produce multiple zombies — I had 3 orphaned processes each at 100% CPU (984 minutes of cumulative CPU time).
Root cause
Two issues in external_plugins/telegram/server.ts:
- Cleanup relies solely on stdin EOF (
process.stdin.on('end', shutdown)at line 629-630) — there is no fallback mechanism (PID lock file, parent-process heartbeat, etc.) to detect that the parent Claude Code process is gone.
- The 409 Conflict retry loop (line 960) has no max-attempt cap — when a zombie holds the polling token, new instances retry forever with only 15s max backoff. Meanwhile the zombie itself is also looping. All of them burn CPU indefinitely.
// line 959-988 — infinite loop, no exit condition
void (async () => {
for (let attempt = 1; ; attempt++) {
try {
await bot.start({ ... })
return
} catch (err) {
if (err instanceof GrammyError && err.error_code === 409) {
const delay = Math.min(1000 * attempt, 15000)
// retries forever...
await new Promise(r => setTimeout(r, delay))
continue
}
...
}
}
Suggested fix
- Add a max retry count (e.g. 10-20) to the 409 loop — exit the process after exhausting retries.
- Implement a PID-file lock or parent-process liveness check so orphaned processes can detect the parent is gone and self-terminate.
Environment
- macOS Darwin 25.4.0
- Telegram plugin version 0.0.4
- Bun runtime
This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗