{"record":{"id":"a3f79700fd99293d","repo":"HKUDS/Vibe-Trading","slug":"wechat-send-media-error-ret-ret-errcode-errco","errorCode":null,"errorMessage":"WeChat send media error (ret={ret}, errcode={errcode}): {data.get('errmsg', '')}","messagePattern":"WeChat send media error \\(ret=(.+?), errcode=(.+?)\\): (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"agent/src/channels/weixin.py","lineNumber":1472,"sourceCode":"            \"to_user_id\": to_user_id,\n            \"client_id\": client_id,\n            \"message_type\": MESSAGE_TYPE_BOT,\n            \"message_state\": MESSAGE_STATE_FINISH,\n            \"item_list\": item_list,\n        }\n        if context_token:\n            weixin_msg[\"context_token\"] = context_token\n\n        body: dict[str, Any] = {\n            \"msg\": weixin_msg,\n            \"base_info\": BASE_INFO,\n        }\n\n        data = await self._api_post(\"ilink/bot/sendmessage\", body)\n        ret = data.get(\"ret\", 0)\n        errcode = data.get(\"errcode\", 0)\n        if (ret is not None and ret != 0) or (errcode is not None and errcode != 0):\n            raise RuntimeError(\n                f\"WeChat send media error (ret={ret}, errcode={errcode}): {data.get('errmsg', '')}\"\n            )\n\n\n# ---------------------------------------------------------------------------\n# AES-128-ECB encryption / decryption  (matches pic-decrypt.ts / aes-ecb.ts)\n# ---------------------------------------------------------------------------\n\n\ndef _parse_aes_key(aes_key_b64: str) -> bytes:\n    \"\"\"Parse a base64-encoded AES key, handling both encodings seen in the wild.\n\n    From ``pic-decrypt.ts parseAesKey``:\n\n    * ``base64(raw 16 bytes)``            → images (media.aes_key)\n    * ``base64(hex string of 16 bytes)``  → file / voice / video\n\n    In the second case base64-decoding yields 32 ASCII hex chars which must","sourceCodeStart":1454,"sourceCodeEnd":1490,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/channels/weixin.py#L1454-L1490","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait weixin_channel.send(msg)  # raises on any nonzero ret/errcode\n\n// after\ntry:\n    await weixin_channel.send(msg)\nexcept RuntimeError as e:\n    if 'errcode=45009' in str(e):\n        await asyncio.sleep(5)\n        await weixin_channel.send(msg)\n    else:\n        raise","handlingStrategy":"try-catch","validationCode":"def is_sendable_media(path: str) -> bool:\n    from pathlib import Path\n    p = Path(path)\n    return p.exists() and p.stat().st_size > 0 and p.suffix.lower() in {'.png', '.jpg', '.jpeg', '.mp4', '.mp3', '.pdf'}","typeGuard":null,"tryCatchPattern":"try:\n    await weixin.send(msg)\nexcept RuntimeError as e:\n    if 'WeChat send media error' in str(e):\n        log.warning('wechat media rejected: %s', e)\n        await asyncio.sleep(backoff)\n        backoff = min(backoff * 2, 60)\n    else:\n        raise","preventionTips":["Validate media file format and size before calling send()","Keep bot credentials fresh; refresh tokens proactively","Rate-limit outbound media sends to avoid 45009"],"tags":["wechat","messaging","api-error","media-upload"],"backgroundTag":"api-error-response","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}