Skip to content

Bot stays alive but never polls after transient getWebhookInfo failure at startup (zombie process, systemd shows running) #222

Description

@insign

Hi, first of all thank you for this great project!

I ran into a case where the bot process looks healthy but never actually polls Telegram, so it stays silent until manually restarted. Sharing details below in case it helps.

Environment

  • Package: @grinev/opencode-telegram-bot v0.25.0 (installed via npm)
  • Node.js v24.18.0 on linux x64
  • Running as systemd system service (opencode-telegram-bot.service, Type=simple, Restart=on-failure, ExecStart=/usr/local/bin/node .../opencode-telegram start)
  • OpenCode server on port 4096 (user unit, healthy)

Symptoms

  • systemctl status opencode-telegram-bot showed active (running), PID alive, memory/CPU normal.
  • Bot did not respond to any Telegram messages (/sessions, /projects, /start stayed as pending updates, pending_update_count grew to 6).
  • Manual getUpdates against the same token succeeded with normal updates (no 409 Conflict), proving no active long-poller was running despite the alive process.
  • After systemctl restart, the bot logged Bot @OChelioBOT started! and manual getUpdates correctly returned 409 Conflict (single healthy poller). Token and network to api.telegram.org were fine the whole time.

Logs (startup that got stuck, IDs redacted)

[INFO] Starting OpenCode Telegram Bot v0.25.0...
[INFO] Allowed User ID: [REDACTED]
[INFO] [OpenCodeAutoRestart] Enabled: port=4096, intervalSec=300
[INFO] [OpenCodeReady] OpenCode server is ready: reason=auto_restart_startup
[INFO] [SessionCache] Pruned 3 stale directories from cache
[INFO] [PinnedManager] Restoring existing pinned message for session: ses_[REDACTED]
[INFO] [PinnedManager] Loaded 41 file diffs from messages
[INFO] [PinnedManager] Loaded context from history: 392732 tokens, cost: $2.35
[INFO] [Bot] Subscribing to OpenCode events for project: /home/.../codewalk
[INFO] [Attach] Attached to session: session=ses_[REDACTED], directory=/home/.../codewalk
[INFO] [Bot] Restored followed session after OpenCode ready: reason=auto_restart_startup
CLI error: Network request for 'getWebhookInfo' failed!

Note what is missing compared to a healthy startup: no [Bot] Dropping ~N update(s) queued while the bot was offline and no Bot @OChelioBOT started!. On healthy boots those two lines appear right after PinnedManager Restoring.... Earlier boots on the same machine also showed transient Could not clear global commands: HttpError: Network request for 'setMyCommands' failed! right before the same stuck state, so it looks like a transient Telegram API hiccup at startup is enough to trigger it.

Suspected cause (from installed dist/, may have shifted in source)

  • dist/app/bootstrap/start-bot-app.js:126: const webhookInfo = await bot.api.getWebhookInfo(); runs before bot.start() with no surrounding try/catch. If it throws, startBotApp() rejects.
  • dist/cli.js:192-203: the top-level runCli(...).catch(...) only writes CLI error: ... to stderr and sets process.exitCode = 1. It does not force exit.
  • Meanwhile background work (opencodeAutoRestartService.start(), scheduledTaskRuntime, heartbeat setInterval in dist/bot/index.js:85, PinnedManager restore via onReady) keeps the event loop alive, so the process never exits.
  • Net effect: bot.start({ drop_pending_updates: true, ... }) at start-bot-app.js:138 is never reached, no polling starts, but systemd still sees active (running) and Restart=on-failure never fires. A zombie that looks healthy.

I did not dig into the TypeScript sources, so paths above are from dist/ — happy to re-check against source if you point me at the right files.

Expected vs actual

  • Expected: a Telegram API failure during startup either retries and then starts polling, or fails fast with process exit so the supervisor restarts it.
  • Actual: process stays alive with exit code pending but no polling, requiring manual systemctl restart.

Possible fixes (just ideas)

  • Wrap the pre-bot.start() Telegram calls (getWebhookInfo, deleteWebhook if needed) with retry + fail-fast process.exit(1) (after flushing logs/settings and stopping background services/timers) so Restart=on-failure works.
  • Or ensure startup failure always tears down heartbeatTimer, opencodeAutoRestartService, scheduledTaskRuntime, and listeners before rethrowing, so Node can actually exit when exitCode is set.
  • Optionally log a clear FATAL: Telegram polling never started line to make the zombie state obvious.

Workaround for others hitting this

sudo systemctl restart opencode-telegram-bot, then confirm Bot @... started! in journalctl -u opencode-telegram-bot and that a manual getUpdates returns 409 Conflict (healthy single poller).

Happy to provide more logs or test a fix. Thanks again for maintaining this!

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions