hermes - 💡(How to fix) Fix [Bug] send_message tool fails with Weixin: Timeout context manager should be used inside a task

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Calling the send_message tool with the weixin platform target fails with:

Weixin send failed: Timeout context manager should be used inside a task

This happens on both text and media messages (including MEDIA:/path/to/file uploads). The error originates from aiohttp/helpers.py:

# aiohttp/helpers.py, line 678
def __enter__(self) -> BaseTimerContext:
    task = asyncio.current_task(loop=self._loop)
    if task is None:
        raise RuntimeError("Timeout context manager should be used inside a task")

The same underlying issue causes text_to_speech to fail with:

TTS generation failed (edge): Connection timeout to host wss://speech.platform.bing.com/...

Error Message

This happens on both text and media messages (including MEDIA:/path/to/file uploads). The error originates from aiohttp/helpers.py:

Root Cause

Trigger path:

  1. send_message_tool._handle_send() -> model_tools._run_async(_send_to_platform(...))
  2. _run_async detects asyncio.get_running_loop().is_running() == True (gateway/CLI loop is already running)
  3. Falls into the thread pool path: ThreadPoolExecutor(max_workers=1).submit(asyncio.run, coro)
  4. asyncio.run() creates a fresh event loop in the worker thread
  5. Inside _send_weixin() -> send_weixin_direct() -> async with aiohttp.ClientSession(...) as session (line 2010 of gateway/platforms/weixin.py)
  6. ClientSession.aenter creates asyncio.timeout(self._timeout) (aiohttp >= 3.9)
  7. asyncio.timeout.enter calls asyncio.current_task(loop=self._loop) which returns None because the Timeout object was initialized with a loop reference that does not match the actual running loop in the worker thread.

Known aiohttp issues:

  • #7542: Timeout Context Manager should be used inside a task - marked Not planned (Aug 2023)
  • #10153: Timeout context manager should be used inside a task slightly misleading - closed (Jan 2025)

Code Example

Weixin send failed: Timeout context manager should be used inside a task

---

# aiohttp/helpers.py, line 678
def __enter__(self) -> BaseTimerContext:
    task = asyncio.current_task(loop=self._loop)
    if task is None:
        raise RuntimeError("Timeout context manager should be used inside a task")

---

TTS generation failed (edge): Connection timeout to host wss://speech.platform.bing.com/...

---

# In a Hermes session with Weixin configured:
send_message(target="weixin", message="test")
# OR
send_message(target="weixin:[email protected]", message="MEDIA:/tmp/test.png")

---

Weixin send failed: Timeout context manager should be used inside a task
RAW_BUFFERClick to expand / collapse

Bug: send_message tool fails with Weixin - Timeout context manager should be used inside a task

Repository: https://github.com/NousResearch/hermes-agent


Description

Calling the send_message tool with the weixin platform target fails with:

Weixin send failed: Timeout context manager should be used inside a task

This happens on both text and media messages (including MEDIA:/path/to/file uploads). The error originates from aiohttp/helpers.py:

# aiohttp/helpers.py, line 678
def __enter__(self) -> BaseTimerContext:
    task = asyncio.current_task(loop=self._loop)
    if task is None:
        raise RuntimeError("Timeout context manager should be used inside a task")

The same underlying issue causes text_to_speech to fail with:

TTS generation failed (edge): Connection timeout to host wss://speech.platform.bing.com/...

Environment

  • Hermes Agent: NousResearch/hermes-agent (latest)
  • Python: 3.11
  • aiohttp: 3.13.5
  • Platform: Weixin (WeChat) via send_message tool
  • Session: Running inside the CLI/gateway with an existing event loop

Root Cause Analysis

Trigger path:

  1. send_message_tool._handle_send() -> model_tools._run_async(_send_to_platform(...))
  2. _run_async detects asyncio.get_running_loop().is_running() == True (gateway/CLI loop is already running)
  3. Falls into the thread pool path: ThreadPoolExecutor(max_workers=1).submit(asyncio.run, coro)
  4. asyncio.run() creates a fresh event loop in the worker thread
  5. Inside _send_weixin() -> send_weixin_direct() -> async with aiohttp.ClientSession(...) as session (line 2010 of gateway/platforms/weixin.py)
  6. ClientSession.aenter creates asyncio.timeout(self._timeout) (aiohttp >= 3.9)
  7. asyncio.timeout.enter calls asyncio.current_task(loop=self._loop) which returns None because the Timeout object was initialized with a loop reference that does not match the actual running loop in the worker thread.

Known aiohttp issues:

  • #7542: Timeout Context Manager should be used inside a task - marked Not planned (Aug 2023)
  • #10153: Timeout context manager should be used inside a task slightly misleading - closed (Jan 2025)

Reproduction Steps

# In a Hermes session with Weixin configured:
send_message(target="weixin", message="test")
# OR
send_message(target="weixin:[email protected]", message="MEDIA:/tmp/test.png")

Expected Behavior

Message is sent successfully to Weixin/WeChat.

Actual Behavior

Weixin send failed: Timeout context manager should be used inside a task

Suggested Fix

The issue is that asyncio.run() in _run_async's thread pool path creates a new loop, but the ClientSession initialization in send_weixin_direct may be receiving a stale loop reference.

  1. For send_weixin_direct: Ensure the ClientSession is created without relying on implicit loop binding, or use explicit loop handling with aiohttp.TCPConnector.

  2. For _run_async: Consider switching the thread pool path to use loop.run_until_complete(coro) on a persistent per-thread loop (matching the non-worker-thread path) instead of asyncio.run(), to avoid the loop reference mismatch.

  3. Alternative: The _run_async docstring mentions When called from a worker thread... use a per-thread persistent loop. The worker thread path already has this (_get_worker_loop().run_until_complete(coro)). Consider whether the main thread path (tool_loop.run_until_complete(coro)) should be used more broadly when the running loop is in the main thread but we are calling from a sync tool handler.

extent analysis

TL;DR

The most likely fix involves ensuring the ClientSession in send_weixin_direct is created without relying on implicit loop binding or using explicit loop handling with aiohttp.TCPConnector, and considering changes to _run_async to avoid loop reference mismatches.

Guidance

  • Explicit Loop Handling: Modify send_weixin_direct to create the ClientSession with an explicit loop reference, ensuring it matches the loop used in the worker thread.
  • Persistent Per-Thread Loop: In _run_async, consider using loop.run_until_complete(coro) on a persistent per-thread loop instead of asyncio.run() to avoid creating a new loop.
  • Unified Loop Usage: Evaluate whether using the main thread path (tool_loop.run_until_complete(coro)) more broadly could simplify loop management and prevent the timeout context manager issue.

Example

# Example of creating ClientSession with explicit loop handling
import aiohttp
import asyncio

loop = asyncio.get_running_loop()
with aiohttp.ClientSession(loop=loop) as session:
    # Use the session
    pass

Notes

The provided suggestions aim to address the loop reference mismatch issue causing the timeout context manager error. However, the optimal solution may depend on the specific requirements and constraints of the Hermes Agent and its interaction with Weixin/WeChat.

Recommendation

Apply the workaround by ensuring explicit loop handling in send_weixin_direct and considering the use of a persistent per-thread loop in _run_async to avoid loop reference mismatches, as this approach directly addresses the identified root cause of the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix [Bug] send_message tool fails with Weixin: Timeout context manager should be used inside a task