Skip to content

Potential Bug: asyncio.create_task lacks strong references in telebot.AsyncTeleBot._process_polling #2572

@fshp971

Description

@fshp971

Bug Description

In the asynchronous polling loop of AsyncTeleBot (e.g., inside telebot.AsyncTeleBot._process_polling), incoming updates are dispatched to process_new_updates using asyncio.create_task(). However, the resulting asyncio.Task object is not assigned to any variable or collection, meaning no strong reference is kept. (See below code block, also see here)

        try:
            while self._polling:
                try:
                    updates = await self.get_updates(offset=self.offset, allowed_updates=allowed_updates, timeout=timeout, request_timeout=request_timeout)
                    if updates:
                        self.offset = updates[-1].update_id + 1
                        # noinspection PyAsyncCall
                        asyncio.create_task(self.process_new_updates(updates)) # Seperate task for processing updates
                    if interval: await asyncio.sleep(interval)
                    error_interval = 0.25 # drop error_interval if no errors

According to the official Python asyncio documentation, the event loop only maintains weak references to tasks. If a task yields control back to the event loop (e.g., awaiting network I/O or a sleep), Python's Garbage Collector (GC) may destroy the unreferenced task mid-execution. This results in the task disappearing silently without raising any exceptions.

I also copy the official explanation from Python documentation (https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task) here to better illustrate the risk:

Important: Save a reference to the result of this function, to avoid a task disappearing mid-execution. The event loop only keeps weak references to tasks. A task that isn’t referenced elsewhere may get garbage collected at any time, even before it’s done. For reliable “fire-and-forget” background tasks, gather them in a collection:

Potential Solution

Add a queue to AsyncTeleBot to store asyncio.Task created via asyncio.create_task() is enough to solve the problem.

If it is ok, I would be happy to create a PR to fix it.

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