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 must

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. 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).
  2. Verify the media file: supported format, non-zero size, within WeChat size limits.
  3. If the error indicates auth/token issues, refresh or re-provision the bot credentials.
  4. 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

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


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/a3f79700fd99293d. Report an issue: GitHub.