From 8ac68df1c96adf491f417df21473121643b452ea Mon Sep 17 00:00:00 2001 From: Polish Hammer Date: Sun, 2 Aug 2026 17:36:59 +0200 Subject: [PATCH] Fix check_self crashing at startup on a None channel check_self starts in setup() (during on_ready), and its first tick can fire before the gateway has populated the channel cache - get_channel() then returns None and channel.history() raises AttributeError. Because an unhandled exception stops a tasks.loop, this also silently killed the log rollover and spontaneous messages the loop is responsible for. Add a before_loop that awaits wait_until_ready() (fixes the startup race) and a None guard that skips the tick with a warning (keeps the loop alive even if the channel is genuinely unreachable: wrong id / not in the guild / missing permission). Co-Authored-By: Claude Opus 4.8 --- administration_commands.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/administration_commands.py b/administration_commands.py index c964d48..cb543f5 100644 --- a/administration_commands.py +++ b/administration_commands.py @@ -171,6 +171,17 @@ class AdministrationModule(commands.Cog): """ # logger.info("Heartbeat of cleanup proc") channel = self.bot.get_channel(1062047367337095268) + if channel is None: + # get_channel() returns None before the gateway cache is populated + # (the before_loop below normally prevents that) or when the bot + # cannot see the channel at all (wrong id / not in the guild / + # missing permission). Skip this tick instead of crashing - an + # unhandled exception here stops the whole loop, killing log + # rollover and the spontaneous messages with it. + self.logger.warning( + "check_self: channel 1062047367337095268 unavailable - skipping tick" + ) + return messages = [message async for message in channel.history(limit=1)] for mess in messages: channel = mess.channel @@ -254,6 +265,13 @@ class AdministrationModule(commands.Cog): self.logger.info(message) await channel.send(message) + @check_self.before_loop + async def before_check_self(self): + # Don't fire the first tick until the gateway is READY and the channel + # cache is populated - get_channel() returns None before that, which is + # exactly what used to crash check_self at startup. + await self.bot.wait_until_ready() + async def setup(bot): logger = logging.getLogger("discord")