Skip to content

[Python lark-oapi 1.6.7] ws/client.py module-level event loop causes RuntimeError when first imported inside a running loop #133

@RookieX

Description

@RookieX

Environment

  • Package: lark-oapi 1.6.7 (Python)
  • Python: 3.9+
  • Affected path: lark_oapi/ws/client.py

Summary

lark_oapi/ws/client.py captures the event loop at module import time via a module-level global. If the module is first imported while an event loop is already running (e.g. inside asyncio.run()), the subsequent loop.run_until_complete(...) raises RuntimeError: This event loop is already running, and the WebSocket long-connection fails immediately.

Root Cause

client.py lines 30-34 run at import time:

try:
    loop = asyncio.get_event_loop()
except RuntimeError:
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

Under Python 3.9, asyncio.get_event_loop() returns the currently running loop when called from within a coroutine / asyncio.run() context, so the module-level loop captures an already-running loop.

client.py then uses this global in start():

# client.py:163, 169, 171, 176
loop.run_until_complete(self._connect())
...
loop.run_until_complete(_select())

Calling run_until_complete on an already-running loop raises RuntimeError: This event loop is already running.

Reproduction

import asyncio

async def main():
    from lark_oapi.ws.client import Client  # first import here captures the running loop
    Client(...).start()                      # RuntimeError: This event loop is already running

asyncio.run(main())

Real-world Trigger

Host applications that lazily import lark_oapi.channel (which transitively imports lark_oapi.ws.client) from within their asyncio main loop hit this unconditionally on first startup.

Suggested Fix

Remove the module-level loop global; create a dedicated event loop per Client instance inside the worker thread in start(), isolating the WS client from the caller's event loop.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions