Discord worker cannot start on Python 3.13: build_bot() raises "no current event loop" #248

Closed
opened 2026-08-13 06:04:19 +00:00 by coilyco-ops · 0 comments
Member

ward exec test has one failing test on main:

FAILED tests/discord/test_worker.py::test_worker_uses_only_non_privileged_intents
RuntimeError: There is no current event loop in thread 'MainThread'.

It is not a test-only problem. The same call path runs in production.

Mechanism

build_bot() constructs discord.Bot(...) synchronously, before bot.run(). Pycord reads the ambient loop during construction, and its compatibility guard only covers Python 3.14 and up — discord/utils.py:

if sys.version_info >= (3, 14):
    try:
        loop = asyncio.get_event_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
    return loop
return asyncio.get_event_loop()   # <- 3.13 takes this branch

On Python 3.13 a bare asyncio.get_event_loop() raises when no loop is running and none has been set. This repo targets 3.13 (target-version = "py313", python_version = "3.13"), so worker.main() raises at build_bot() before it ever reaches bot.run().

The two sibling tests pass only because they assert on RuntimeError raised by the env-var validation, which happens before the discord.Bot(...) call.

Versions: py-cord 2.8.0, pinned >=2.6.1,<3.0.0.

Fix

Ensure a current event loop exists before constructing the Bot — the same thing pycord does for itself on 3.14. Do nothing when a loop is already running or already set.

Acceptance

  • ward exec test is green, with no pre-existing failure to explain away.
  • build_bot() is covered by a test that constructs the Bot outside a running loop, which is how main() calls it.
  • main() still runs the bot on the loop that gets created.

Origin

Noticed as the standing red test while working the 2026-08-12 QA sweep (#240). It predates that work — it is on main independently.

`ward exec test` has one failing test on `main`: ``` FAILED tests/discord/test_worker.py::test_worker_uses_only_non_privileged_intents RuntimeError: There is no current event loop in thread 'MainThread'. ``` It is not a test-only problem. The same call path runs in production. ## Mechanism `build_bot()` constructs `discord.Bot(...)` synchronously, before `bot.run()`. Pycord reads the ambient loop during construction, and its compatibility guard only covers Python 3.14 and up — `discord/utils.py`: ```python if sys.version_info >= (3, 14): try: loop = asyncio.get_event_loop() except RuntimeError: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) return loop return asyncio.get_event_loop() # <- 3.13 takes this branch ``` On Python 3.13 a bare `asyncio.get_event_loop()` raises when no loop is running and none has been set. This repo targets 3.13 (`target-version = "py313"`, `python_version = "3.13"`), so `worker.main()` raises at `build_bot()` before it ever reaches `bot.run()`. The two sibling tests pass only because they assert on `RuntimeError` raised by the env-var validation, which happens before the `discord.Bot(...)` call. Versions: py-cord 2.8.0, pinned `>=2.6.1,<3.0.0`. ## Fix Ensure a current event loop exists before constructing the Bot — the same thing pycord does for itself on 3.14. Do nothing when a loop is already running or already set. ## Acceptance - `ward exec test` is green, with no pre-existing failure to explain away. - `build_bot()` is covered by a test that constructs the Bot outside a running loop, which is how `main()` calls it. - `main()` still runs the bot on the loop that gets created. ## Origin Noticed as the standing red test while working the 2026-08-12 QA sweep (https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/240). It predates that work — it is on `main` independently.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/eco-app#248
No description provided.