node-telegram-bot-api: The Offset Infinite Loop

Hi My bot has been stuck in infinite loop and it’s not responding anymore, what’s problem? here is the stack trace:

Unhandled rejection Error: 403 {"ok":false,"error_code":403,"description":"Error: Bot was kicked from a chat"}
    at /Users/vahid/Desktop/node_modules/node-telegram-bot-api/src/telegram.js:72:15
    at tryCatcher (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/util.js:26:23)
    at Promise._settlePromiseFromHandler (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/promise.js:503:31)
    at Promise._settlePromiseAt (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/promise.js:577:18)
    at Promise._settlePromises (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/promise.js:693:14)
    at Async._drainQueue (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/async.js:123:16)
    at Async._drainQueues (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/async.js:133:10)
    at Immediate.Async.drainQueues [as _onImmediate] (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/async.js:15:14)
    at processImmediate [as _immediateCallback] (timers.js:367:17)
Unhandled rejection Error: 403 {"ok":false,"error_code":403,"description":"Error: Bot was kicked from a chat"}
    at /Users/vahid/Desktop/node_modules/node-telegram-bot-api/src/telegram.js:72:15
    at tryCatcher (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/util.js:26:23)
    at Promise._settlePromiseFromHandler (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/promise.js:503:31)
    at Promise._settlePromiseAt (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/promise.js:577:18)
    at Promise._settlePromises (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/promise.js:693:14)
    at Async._drainQueue (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/async.js:123:16)
    at Async._drainQueues (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/async.js:133:10)
    at Immediate.Async.drainQueues [as _onImmediate] (/Users/vahid/Desktop/node_modules/node-telegram-bot-api/node_modules/bluebird/js/main/async.js:15:14)
    at processImmediate [as _immediateCallback] (timers.js:367:17)

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 32 (3 by maintainers)

Commits related to this issue

Most upvoted comments

This should be fixed by commit 178f9cd9051b63377fcbb3a13f564b175b1cd3e7. The matter was it wasn’t updating the offset if there was an error and can’t reach the last message. Now every message processed updates the offset.

This is what I have gathered so far:


when and how does the bug occur?

The bug occurs when an error is thrown during processing of an update.

During this processing of an update (at src/telegramPolling.js#L46), an error could be thrown while:

Such an error would bubble up and be handled by the enveloping promise (see src/telegramPolling.js#L40). The promise would simply re-throw the error (at src/telegramPolling.js#L51). This results in the “Unhandled rejection Error” as seen above. So far, such unhandled errors do NOT terminate the Node.js process. The unterminated process will continue polling (see src/telegramPolling.js#L58)!

However, @yagop’s fix, updates the offset before processing an update. Since an update is considered confirmed as soon as getUpdates is called with an offset higher than its update_id, all the updates received, including the update that caused the chain of errors to occur, would be confirmed, as soon as we enter the next poll interval (see src/telegramPolling.js#L94). Thus, the fix (kinda) works!

Before the fix, the offset would not have been updated (see old code at src/telegramPolling.js#L34), causing the next poll interval to retrieve already-processed updates, including the update that originally caused the error! Thus LOOP!

Note that if the process terminated and we restarted it again, this bug would re-surface since we would not have marked the already-processed updates as confirmed! This is important considering that in the future, unhandled promise rejections will terminate the process. Thus, the fix will stop working some time in the future!

In some cases, the bug would disappear, as the offending update would have been discarded by Telegram after their 24hr limit!


fixing:

It is currently fixed!!!

The current fix works, as long as unhandled promise rejections do not terminate the process. Once Node.js behaves by terminating, this loop will re-surface! To prevent this Loop completely, we need a way to consider this:

  1. Processed updates MUST be marked confirmed
  2. The update causing the error may remain unconfirmed to allow re-processing (we need more discussion around this)

To achieve the above, in our .catch() (at src/telegramPolling.js#L49), we may do the following, in order:

  1. send a getUpdates request with the updated offset + 1, therefore marking all processed updates as confirmed!
  2. re-throw the error, thus terminating the process!

notes:

Reproducing this bug is important. If you believe that this bug has not been fixed, please provide an elaborate way to reproduce it. (@yagop had a hard time doing so)


related issues:

  • Offset Issue if Error: #15
  • Stickers will crash!: #16

@witnessmenow I just used telegram api url, manually entered offset like this:

/getUpdates?offset=415204539

+1-ing every time I got update_id in json. So after some iterations I got rid of old messages.

Problem is not with telegram I think. Something wrong with incrementing update_id in code. If I encounter this problem again I will try to find a solution and create PR.