Skip to content

fix(weixin): send_weixin_direct cross-loop session causes "Timeout context manager should be used inside a task" - #18890

Closed
MottledShadow wants to merge 1 commit into
NousResearch:mainfrom
MottledShadow:fix/weixin-crossloop-send-message
Closed

fix(weixin): send_weixin_direct cross-loop session causes "Timeout context manager should be used inside a task"#18890
MottledShadow wants to merge 1 commit into
NousResearch:mainfrom
MottledShadow:fix/weixin-crossloop-send-message

Conversation

@MottledShadow

Copy link
Copy Markdown
Contributor

Problem

When send_message tool is invoked from inside a running gateway (e.g., CLI → send_message to weixin), the send_message tool handler is async and _run_async() spawns a worker thread with a separate event loop. send_weixin_direct() then prefers reusing the live adapter's aiohttp session — but that session was created on the gateway's main loop.

aiohttp 3.13.5's TimerContext.__enter__() calls:

task = asyncio.current_task(loop=self._loop)
if task is None:
    raise RuntimeError("Timeout context manager should be used inside a task")

Since we are executing on the worker thread loop, current_task(loop=gateway_loop) returns None, and every send attempt fails (5 retries with backoff, then error).

This affects:

  • send_message text delivery to weixin
  • send_message MEDIA: file delivery to weixin
  • cron job delivery to weixin

Normal inbound→reply works fine because it runs entirely on the gateway's main loop.

Fix

Before using the live adapter path, verify the session's event loop matches the current execution loop:

if (live_adapter is not None and send_session is not None
        and not send_session.closed
        and send_session._loop is asyncio.get_running_loop()):

When loops differ, fall through to the existing fresh-session path (new aiohttp.ClientSession()), which already works correctly.

The feishu adapter avoids this issue entirely by always creating a new adapter instance in _send_feishu() — it never touches the live adapter.

Testing

  • send_message text to weixin
  • send_message MEDIA: file attachment to weixin
  • Normal inbound→reply still works (untouched code path)

Notes

Uses session._loop (aiohttp private attribute) for loop comparison. An alternative would be to fix this at the _run_async level so gateway-session-bound tools stay on the main loop, but that would be a wider change and we judged this targeted fix to be the right tradeoff.

When send_message tool is called from inside a running gateway, the
_run_async bridge spawns a worker thread with a separate event loop.
send_weixin_direct then reuses the live adapter's aiohttp session
which was created on the gateway's main loop.  aiohttp's TimerContext
checks asyncio.current_task(loop=session._loop) and sees None because
we're executing on the worker thread's loop → raises 'Timeout context
manager should be used inside a task'.

Fix: skip the live-adapter shortcut when the session belongs to a
different event loop, falling through to the fresh-session path.
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #13350 — same cross-event-loop aiohttp session reuse in send_weixin_direct(). Multiple prior PRs address this same root cause: #13361, #14481, #13520.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/wecom WeCom / WeChat Work adapter labels May 2, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #13350

@teknium1

teknium1 commented May 3, 2026

Copy link
Copy Markdown
Contributor

Merged via PR #19141: #19141

Your fix was cherry-picked onto current main with your authorship preserved — commit a22465e shows up as yours in git log. Thanks for the clean diagnosis and the minimal fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/wecom WeCom / WeChat Work adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants