BUG-HUNT: [concurrency] Node.execute and _execute_function call deprecated asyncio.get_event_loop() inside async methods — RuntimeError in Python 3.12+ #6522

Open
opened 2026-04-09 21:14:41 +00:00 by HAL9000 · 0 comments
Owner

Bug Report: [concurrency] — Deprecated asyncio.get_event_loop() Used Inside async def Methods

Severity Assessment

  • Impact: asyncio.get_event_loop() is deprecated for use inside coroutines in Python 3.10+ and raises DeprecationWarning. In Python 3.12+, calling it when there is no current event loop (e.g., in a new thread) raises RuntimeError instead of creating a new loop. Node execution will fail at runtime in Python 3.12+ environments when called from thread pool executors.
  • Likelihood: Medium — affects any environment running Python 3.12+ or receiving deprecation-as-error treatment.
  • Priority: Medium

Location

  • File: src/cleveragents/langgraph/nodes.py
  • Class: Node
  • Methods: execute (line ~90), _execute_function (line ~175)

Description

Both Node.execute() and Node._execute_function() are async def methods that call asyncio.get_event_loop(). Inside a running coroutine, the correct API is asyncio.get_running_loop(), which is always available and never deprecated.

Evidence

In execute():

async def execute(self, state: GraphState) -> dict[str, Any]:
    self.execution_count += 1
    loop = asyncio.get_event_loop()       # <-- deprecated; should be get_running_loop()
    start_time = loop.time()
    try:
        ...
    finally:
        self.last_execution_time = loop.time() - start_time

In _execute_function():

async def _execute_function(self, state: GraphState) -> dict[str, Any]:
    ...
    else:
        loop = asyncio.get_event_loop()   # <-- deprecated; should be get_running_loop()
        result = await loop.run_in_executor(None, lambda: fn(state))

From Python 3.10 changelog:

Deprecation warning is emitted when get_event_loop() is called and there is no running event loop... In future Python release this will become an error.

From Python 3.12 changelog:

get_event_loop() now emits a DeprecationWarning if there is no current event loop. In some future Python release this will become an error.

When sync_executor in _register_node_executor calls asyncio.run(async_executor(msg)) inside a ThreadPoolExecutor, the newly created thread has no running event loop. If execute() (called inside async_executor) then calls asyncio.get_event_loop(), it will fail in Python 3.12+ because the running loop from asyncio.run() is accessible via get_running_loop() — but the outer call to get_event_loop() in a subthread context may not work reliably.

Expected Behavior

All code inside async def methods should use asyncio.get_running_loop() to obtain the current event loop. This is guaranteed to succeed (the loop is always running when a coroutine executes) and is the correct, non-deprecated API.

Actual Behavior

asyncio.get_event_loop() is called instead, producing DeprecationWarning on Python 3.10/3.11 and potentially RuntimeError in certain Python 3.12+ threading contexts.

Suggested Fix

# In execute():
loop = asyncio.get_running_loop()   # replace get_event_loop()

# In _execute_function():
loop = asyncio.get_running_loop()   # replace get_event_loop()

Category

concurrency

TDD Note

After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. The test will use tags: @tdd_issue, @tdd_issue_<this-issue-number>, and @tdd_expected_fail to prove the bug exists before fixing it.


Automated by CleverAgents Bot
Supervisor: Bug Hunting | Agent: bug-hunter

## Bug Report: [concurrency] — Deprecated `asyncio.get_event_loop()` Used Inside `async def` Methods ### Severity Assessment - **Impact**: `asyncio.get_event_loop()` is deprecated for use inside coroutines in Python 3.10+ and raises `DeprecationWarning`. In Python 3.12+, calling it when there is no current event loop (e.g., in a new thread) raises `RuntimeError` instead of creating a new loop. Node execution will fail at runtime in Python 3.12+ environments when called from thread pool executors. - **Likelihood**: Medium — affects any environment running Python 3.12+ or receiving deprecation-as-error treatment. - **Priority**: Medium ### Location - **File**: `src/cleveragents/langgraph/nodes.py` - **Class**: `Node` - **Methods**: `execute` (line ~90), `_execute_function` (line ~175) ### Description Both `Node.execute()` and `Node._execute_function()` are `async def` methods that call `asyncio.get_event_loop()`. Inside a running coroutine, the correct API is `asyncio.get_running_loop()`, which is always available and never deprecated. ### Evidence **In `execute()`:** ```python async def execute(self, state: GraphState) -> dict[str, Any]: self.execution_count += 1 loop = asyncio.get_event_loop() # <-- deprecated; should be get_running_loop() start_time = loop.time() try: ... finally: self.last_execution_time = loop.time() - start_time ``` **In `_execute_function()`:** ```python async def _execute_function(self, state: GraphState) -> dict[str, Any]: ... else: loop = asyncio.get_event_loop() # <-- deprecated; should be get_running_loop() result = await loop.run_in_executor(None, lambda: fn(state)) ``` From Python 3.10 changelog: > Deprecation warning is emitted when `get_event_loop()` is called and there is no running event loop... In future Python release this will become an error. From Python 3.12 changelog: > `get_event_loop()` now emits a DeprecationWarning if there is no current event loop. In some future Python release this will become an error. When `sync_executor` in `_register_node_executor` calls `asyncio.run(async_executor(msg))` inside a `ThreadPoolExecutor`, the newly created thread has no running event loop. If `execute()` (called inside `async_executor`) then calls `asyncio.get_event_loop()`, it will fail in Python 3.12+ because the running loop from `asyncio.run()` is accessible via `get_running_loop()` — but the outer call to `get_event_loop()` in a subthread context may not work reliably. ### Expected Behavior All code inside `async def` methods should use `asyncio.get_running_loop()` to obtain the current event loop. This is guaranteed to succeed (the loop is always running when a coroutine executes) and is the correct, non-deprecated API. ### Actual Behavior `asyncio.get_event_loop()` is called instead, producing `DeprecationWarning` on Python 3.10/3.11 and potentially `RuntimeError` in certain Python 3.12+ threading contexts. ### Suggested Fix ```python # In execute(): loop = asyncio.get_running_loop() # replace get_event_loop() # In _execute_function(): loop = asyncio.get_running_loop() # replace get_event_loop() ``` ### Category `concurrency` ### TDD Note After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. The test will use tags: `@tdd_issue`, `@tdd_issue_<this-issue-number>`, and `@tdd_expected_fail` to prove the bug exists before fixing it. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: bug-hunter
HAL9000 added this to the v3.2.0 milestone 2026-04-09 21:27:54 +00:00
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
cleveragents/cleveragents-core#6522
No description provided.