Hmbown/CodeWhale · error

Telegram getUpdates conflict; another bridge is polling…

Error message

Telegram getUpdates conflict; another bridge is polling this bot token. Stop the other bridge process or use a different token.

What it means

Telegram's Bot API allows only one getUpdates (long-poll) consumer per bot token. When the bridge detects a 409 polling conflict, it retries with backoff a limited number of times (pollingConflictAttempts); once the delay budget is exhausted it throws this terminal error. It means another process — often a duplicate bridge or a webhook-configured bot — is competing for the same token.

Solutions

  1. Find and stop the other process polling the same token (ps aux | grep telegram-bridge, check other hosts/containers).
  2. Use a different bot token (create a new bot via @BotFather) for one of the instances.
  3. If a webhook is set, delete it: call deleteWebhook for the token, since webhooks conflict with getUpdates.
  4. Restart only one bridge instance after confirming no duplicate is running.

Example fix

// before (two terminals, same token)
BRIDGE_TELEGRAM_BOT_TOKEN=A... node src/index.mjs  # terminal 1
BRIDGE_TELEGRAM_BOT_TOKEN=A... node src/index.mjs  # terminal 2 -> conflict

// after
BRIDGE_TELEGRAM_BOT_TOKEN=A... node src/index.mjs  # terminal 1
BRIDGE_TELEGRAM_BOT_TOKEN=B... node src/index.mjs  # terminal 2, distinct bot
Defensive patterns

Strategy: retry

Validate before calling

// Before starting, verify no other consumer: if a webhook is set, getUpdates will conflict.
const me = await fetch(`https://api.telegram.org/bot${token}/getWebhookInfo`).then((r) => r.json());
if (me.result?.url) {
  await fetch(`https://api.telegram.org/bot${token}/deleteWebhook`, { method: "POST" });
}

Try / catch

try {
  await pollTelegram();
} catch (err) {
  if (err instanceof Error && err.message.includes("getUpdates conflict")) {
    console.error("Another process is polling this bot token. Stop it or use a different token.");
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: pollTelegram's fetch fails with a polling-conflict error (looksLikePollingConflict true) on every retry until telegramPollingConflictDelayMs returns null, i.e. a second process has been calling getUpdates with the same bot token for the whole backoff window.

Common situations: Two bridge instances running locally or on different hosts with the same TELEGRAM_BOT_TOKEN, an old process that never died, a dev instance and a production instance sharing a token, or a webhook left enabled on the bot.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/881412428dfb604a. Report an issue: GitHub.

Appendix: source

Thrown at integrations/telegram-bridge/src/index.mjs:147

        timeout: config.pollTimeoutSeconds,
        allowed_updates: ["message", "callback_query"]
      });
      pollingConflictAttempts = 0;
      for (const update of updates || []) {
        try {
          await handleIncomingUpdate(update);
          await markUpdateHandled(update);
        } catch (error) {
          console.error("failed to handle incoming Telegram update", error);
          break;
        }
      }
    } catch (error) {
      if (looksLikePollingConflict(error)) {
        const waitMs = telegramPollingConflictDelayMs(pollingConflictAttempts);
        pollingConflictAttempts += 1;
        if (waitMs == null) {
          throw new Error(
            "Telegram getUpdates conflict; another bridge is polling this bot token. Stop the other bridge process or use a different token."
          );
        }
        console.warn(
          `Telegram getUpdates conflict; another bridge is polling this bot. Retrying in ${Math.round(waitMs / 1000)}s.`
        );
        await delay(waitMs);
        continue;
      }
      pollingConflictAttempts = 0;
      const waitMs = telegramRetryDelayMs(error);
      console.error(`Telegram poll failed: ${error.message}. Retrying in ${Math.round(waitMs / 1000)}s.`);
      await delay(waitMs);
    }
  }
}

async function markUpdateHandled(update) {

View on GitHub (pinned to 433685b202)