HKUDS/Vibe-Trading · error · RuntimeError
WeChat send media error (ret={ret}, errcode={errcode}): {dat
Error message
WeChat send media error (ret={ret}, errcode={errcode}): {data.get('errmsg', '')} What it means
Raised by _send_media_file when the WeChat ilink/bot/sendmessage API returns a nonzero ret or errcode after attempting to send a media file. The response body's errmsg is included, so the underlying cause (invalid media, expired token, size limit, rate limit) is visible in the message. This is a remote API rejection, not a local exception, so retrying only helps for transient errcodes.
Source
Thrown at agent/src/channels/weixin.py:1472
"to_user_id": to_user_id,
"client_id": client_id,
"message_type": MESSAGE_TYPE_BOT,
"message_state": MESSAGE_STATE_FINISH,
"item_list": item_list,
}
if context_token:
weixin_msg["context_token"] = context_token
body: dict[str, Any] = {
"msg": weixin_msg,
"base_info": BASE_INFO,
}
data = await self._api_post("ilink/bot/sendmessage", body)
ret = data.get("ret", 0)
errcode = data.get("errcode", 0)
if (ret is not None and ret != 0) or (errcode is not None and errcode != 0):
raise RuntimeError(
f"WeChat send media error (ret={ret}, errcode={errcode}): {data.get('errmsg', '')}"
)
# ---------------------------------------------------------------------------
# AES-128-ECB encryption / decryption (matches pic-decrypt.ts / aes-ecb.ts)
# ---------------------------------------------------------------------------
def _parse_aes_key(aes_key_b64: str) -> bytes:
"""Parse a base64-encoded AES key, handling both encodings seen in the wild.
From ``pic-decrypt.ts parseAesKey``:
* ``base64(raw 16 bytes)`` → images (media.aes_key)
* ``base64(hex string of 16 bytes)`` → file / voice / video
In the second case base64-decoding yields 32 ASCII hex chars which mustView on GitHub (pinned to 80ffdda44c)
Solutions
- Inspect the errmsg and errcode in the raised message — WeChat errcode tables identify the exact cause (e.g. 40005 invalid file type, 45009 rate limit).
- Verify the media file: supported format, non-zero size, within WeChat size limits.
- If the error indicates auth/token issues, refresh or re-provision the bot credentials.
- For transient errcodes (rate limit), wrap send() in retry with exponential backoff.
Example fix
// before
await weixin_channel.send(msg) # raises on any nonzero ret/errcode
// after
try:
await weixin_channel.send(msg)
except RuntimeError as e:
if 'errcode=45009' in str(e):
await asyncio.sleep(5)
await weixin_channel.send(msg)
else:
raise Defensive patterns
Strategy: try-catch
Validate before calling
def is_sendable_media(path: str) -> bool:
from pathlib import Path
p = Path(path)
return p.exists() and p.stat().st_size > 0 and p.suffix.lower() in {'.png', '.jpg', '.jpeg', '.mp4', '.mp3', '.pdf'} Try / catch
try:
await weixin.send(msg)
except RuntimeError as e:
if 'WeChat send media error' in str(e):
log.warning('wechat media rejected: %s', e)
await asyncio.sleep(backoff)
backoff = min(backoff * 2, 60)
else:
raise Prevention
- Validate media file format and size before calling send()
- Keep bot credentials fresh; refresh tokens proactively
- Rate-limit outbound media sends to avoid 45009
When it happens
Trigger: Calling send() on the WeChat channel with media attachments where the upstream API responds with ret != 0 or errcode != 0 — e.g. unsupported media type, file too large, expired/invalid bot credentials, or WeChat-side throttling.
Common situations: Media file path exists but format is not supported by WeChat; access token expired mid-session; sending too many media messages in quick succession; sandbox vs production credentials mixed up.
Related errors
- getuploadurl returned no upload URL (need upload_full_url or
- Failed to get QR code from WeChat API: {data}
- getUpdates failed: ret={ret} errcode={errcode} errmsg={data.
- WeChat send text error (ret={ret}, errcode={errcode}): {data
- Media file not found: {media_path}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/a3f79700fd99293d.
Report an issue: GitHub.