Describe the bug
When a TimeoutException occurs during updates.getChannelDifference, the background update-polling fiber crashes and stops fetching new updates entirely.
However, the main EventLoop and outbound connections remain alive (the bot can still catch the exception and send error messages to a Telegram chat). The core issue is that MadelineProto does not automatically recover or restart the update loop after this specific timeout, leaving the bot deaf to new updates until manually restarted via $this->restart().
To Reproduce
It happens randomly due to network timeouts when the bot tries to fetch updates via updates.getChannelDifference.
Expected behavior
MadelineProto should catch the timeout internally and retry fetching updates, or automatically restart the polling fiber, rather than letting the update loop die while the rest of the bot stays alive.
Stack trace
Surfaced: Amp\TimeoutException: Timeout while waiting for updates.getChannelDifference (Enable assertions for a backtrace of the Amp\TimeoutCancellation creation) in /bot/vendor/amphp/amp/src/TimeoutCancellation.php:36
Stack trace:
#0 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(629): Amp\TimeoutCancellation::{closure:Amp\TimeoutCancellation::__construct():29}()
#1 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createCallbackFiber():593}()
#2 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(525): Fiber->resume()
#3 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(586): Revolt\EventLoop\Internal\AbstractDriver->invokeCallbacks()
#4 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createLoopFiber():566}()
#5 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(96): Fiber->resume()
#6 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php(119): Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::__construct():90}()
#7 /bot/vendor/amphp/amp/src/Future.php(252): Revolt\EventLoop\Internal\DriverSuspension->suspend()
#8 /bot/vendor/danog/madelineproto/src/Wrappers/Loop.php(107): Amp\Future->await()
#9 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(86): danog\MadelineProto\MTProto->loop()
#10 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(67): danog\MadelineProto\AbstractAPI->startAndLoopLogic()
#11 /bot/vendor/danog/madelineproto/src/EventHandler.php(180): danog\MadelineProto\AbstractAPI->startAndLoopInternal()
#12 /bot/index.php(42): danog\MadelineProto\EventHandler::startAndLoopBot()
#13 {main}
Next Amp\CancelledException: The operation was cancelled in /bot/vendor/amphp/amp/src/Internal/Cancellable.php:57
Stack trace:
#0 /bot/vendor/amphp/amp/src/Internal/Cancellable.php(48): Amp\Internal\Cancellable->getException()
#1 /bot/vendor/amphp/amp/src/TimeoutCancellation.php(36): Amp\Internal\Cancellable->cancel()
#2 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(629): Amp\TimeoutCancellation::{closure:Amp\TimeoutCancellation::__construct():29}()
#3 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createCallbackFiber():593}()
#4 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(525): Fiber->resume()
#5 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(586): Revolt\EventLoop\Internal\AbstractDriver->invokeCallbacks()
#6 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createLoopFiber():566}()
#7 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(96): Fiber->resume()
#8 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php(119): Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::__construct():90}()
#9 /bot/vendor/amphp/amp/src/Future.php(252): Revolt\EventLoop\Internal\DriverSuspension->suspend()
#10 /bot/vendor/danog/madelineproto/src/Wrappers/Loop.php(107): Amp\Future->await()
#11 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(86): danog\MadelineProto\MTProto->loop()
#12 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(67): danog\MadelineProto\AbstractAPI->startAndLoopLogic()
#13 /bot/vendor/danog/madelineproto/src/EventHandler.php(180): danog\MadelineProto\AbstractAPI->startAndLoopInternal()
#14 /bot/index.php(42): danog\MadelineProto\EventHandler::startAndLoopBot()
#15 {main}
Surfaced: Amp\TimeoutException: Timeout while waiting for updates.getChannelDifference (Enable assertions for a backtrace of the Amp\TimeoutCancellation creation) in /bot/vendor/amphp/amp/src/TimeoutCancellation.php:36
Stack trace:
#0 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(629): Amp\TimeoutCancellation::{closure:Amp\TimeoutCancellation::__construct():29}()
#1 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createCallbackFiber():593}()
#2 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php(65): Fiber->resume()
#3 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(453): Revolt\EventLoop\Internal\DriverSuspension::{closure:Revolt\EventLoop\Internal\DriverSuspension::resume():62}()
#4 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(595): Revolt\EventLoop\Internal\AbstractDriver->invokeMicrotasks()
#5 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createCallbackFiber():593}()
#6 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(530): Fiber->start()
#7 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(586): Revolt\EventLoop\Internal\AbstractDriver->invokeCallbacks()
#8 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createLoopFiber():566}()
#9 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(96): Fiber->resume()
#10 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php(119): Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::__construct():90}()
#11 /bot/vendor/amphp/amp/src/Future.php(252): Revolt\EventLoop\Internal\DriverSuspension->suspend()
#12 /bot/vendor/danog/madelineproto/src/Wrappers/Loop.php(107): Amp\Future->await()
#13 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(86): danog\MadelineProto\MTProto->loop()
#14 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(67): danog\MadelineProto\AbstractAPI->startAndLoopLogic()
#15 /bot/vendor/danog/madelineproto/src/EventHandler.php(180): danog\MadelineProto\AbstractAPI->startAndLoopInternal()
#16 /bot/index.php(42): danog\MadelineProto\EventHandler::startAndLoopBot()
#17 {main}
Next Amp\CancelledException: The operation was cancelled in /bot/vendor/amphp/amp/src/Internal/Cancellable.php:57
Stack trace:
#0 /bot/vendor/amphp/amp/src/Internal/Cancellable.php(48): Amp\Internal\Cancellable->getException()
#1 /bot/vendor/amphp/amp/src/TimeoutCancellation.php(36): Amp\Internal\Cancellable->cancel()
#2 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(629): Amp\TimeoutCancellation::{closure:Amp\TimeoutCancellation::__construct():29}()
#3 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createCallbackFiber():593}()
#4 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php(65): Fiber->resume()
#5 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(453): Revolt\EventLoop\Internal\DriverSuspension::{closure:Revolt\EventLoop\Internal\DriverSuspension::resume():62}()
#6 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(595): Revolt\EventLoop\Internal\AbstractDriver->invokeMicrotasks()
#7 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createCallbackFiber():593}()
#8 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(530): Fiber->start()
#9 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(586): Revolt\EventLoop\Internal\AbstractDriver->invokeCallbacks()
#10 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createLoopFiber():566}()
#11 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(96): Fiber->resume()
#12 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php(119): Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::__construct():90}()
#13 /bot/vendor/amphp/amp/src/Future.php(252): Revolt\EventLoop\Internal\DriverSuspension->suspend()
#14 /bot/vendor/danog/madelineproto/src/Wrappers/Loop.php(107): Amp\Future->await()
#15 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(86): danog\MadelineProto\MTProto->loop()
#16 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(67): danog\MadelineProto\AbstractAPI->startAndLoopLogic()
#17 /bot/vendor/danog/madelineproto/src/EventHandler.php(180): danog\MadelineProto\AbstractAPI->startAndLoopInternal()
#18 /bot/index.php(42): danog\MadelineProto\EventHandler::startAndLoopBot()
#19 {main}
Surfaced: Amp\TimeoutException: Timeout while waiting for updates.getDifference (Enable assertions for a backtrace of the Amp\TimeoutCancellation creation) in /bot/vendor/amphp/amp/src/TimeoutCancellation.php:36
Stack trace:
#0 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(629): Amp\TimeoutCancellation::{closure:Amp\TimeoutCancellation::__construct():29}()
#1 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createCallbackFiber():593}()
#2 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(525): Fiber->resume()
#3 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(586): Revolt\EventLoop\Internal\AbstractDriver->invokeCallbacks()
#4 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createLoopFiber():566}()
#5 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(96): Fiber->resume()
#6 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php(119): Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::__construct():90}()
#7 /bot/vendor/amphp/amp/src/Future.php(252): Revolt\EventLoop\Internal\DriverSuspension->suspend()
#8 /bot/vendor/danog/madelineproto/src/Wrappers/Loop.php(107): Amp\Future->await()
#9 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(86): danog\MadelineProto\MTProto->loop()
#10 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(67): danog\MadelineProto\AbstractAPI->startAndLoopLogic()
#11 /bot/vendor/danog/madelineproto/src/EventHandler.php(180): danog\MadelineProto\AbstractAPI->startAndLoopInternal()
#12 /bot/index.php(42): danog\MadelineProto\EventHandler::startAndLoopBot()
#13 {main}
Next Amp\CancelledException: The operation was cancelled in /bot/vendor/amphp/amp/src/Internal/Cancellable.php:57
Stack trace:
#0 /bot/vendor/amphp/amp/src/Internal/Cancellable.php(48): Amp\Internal\Cancellable->getException()
#1 /bot/vendor/amphp/amp/src/TimeoutCancellation.php(36): Amp\Internal\Cancellable->cancel()
#2 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(629): Amp\TimeoutCancellation::{closure:Amp\TimeoutCancellation::__construct():29}()
#3 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createCallbackFiber():593}()
#4 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(525): Fiber->resume()
#5 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(586): Revolt\EventLoop\Internal\AbstractDriver->invokeCallbacks()
#6 [internal function]: Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::createLoopFiber():566}()
#7 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/AbstractDriver.php(96): Fiber->resume()
#8 /bot/vendor/revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php(119): Revolt\EventLoop\Internal\AbstractDriver->{closure:Revolt\EventLoop\Internal\AbstractDriver::__construct():90}()
#9 /bot/vendor/amphp/amp/src/Future.php(252): Revolt\EventLoop\Internal\DriverSuspension->suspend()
#10 /bot/vendor/danog/madelineproto/src/Wrappers/Loop.php(107): Amp\Future->await()
#11 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(86): danog\MadelineProto\MTProto->loop()
#12 /bot/vendor/danog/madelineproto/src/AbstractAPI.php(67): danog\MadelineProto\AbstractAPI->startAndLoopLogic()
#13 /bot/vendor/danog/madelineproto/src/EventHandler.php(180): danog\MadelineProto\AbstractAPI->startAndLoopInternal()
#14 /bot/index.php(42): danog\MadelineProto\EventHandler::startAndLoopBot()
#15 {main}
Describe the bug
When a
TimeoutExceptionoccurs duringupdates.getChannelDifference, the background update-polling fiber crashes and stops fetching new updates entirely.However, the main EventLoop and outbound connections remain alive (the bot can still catch the exception and send error messages to a Telegram chat). The core issue is that MadelineProto does not automatically recover or restart the update loop after this specific timeout, leaving the bot deaf to new updates until manually restarted via
$this->restart().To Reproduce
It happens randomly due to network timeouts when the bot tries to fetch updates via
updates.getChannelDifference.Expected behavior
MadelineProto should catch the timeout internally and retry fetching updates, or automatically restart the polling fiber, rather than letting the update loop die while the rest of the bot stays alive.
Stack trace