{"record":{"id":"09a6a60f297349cf","repo":"binarywang/WxJava","slug":"getmediadata-err-ret","errorCode":null,"errorMessage":"getmediadata err ret {}","messagePattern":"getmediadata err ret (.+?)","errorType":"exception","errorClass":"WxErrorException","httpStatus":null,"severity":"error","filePath":"weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java","lineNumber":269,"sourceCode":"    });\n  }\n\n  @Override\n  public void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout, @NonNull Consumer<byte[]> action) throws WxErrorException {\n    /**\n     * 1、媒体文件每次拉取的最大size为512k，因此超过512k的文件需要分片拉取。\n     * 2、若该文件未拉取完整，sdk的IsMediaDataFinish接口会返回0，同时通过GetOutIndexBuf接口返回下次拉取需要传入GetMediaData的indexbuf。\n     * 3、indexbuf一般格式如右侧所示，”Range:bytes=524288-1048575“:表示这次拉取的是从524288到1048575的分片。单个文件首次拉取填写的indexbuf为空字符串，拉取后续分片时直接填入上次返回的indexbuf即可。\n     */\n    String indexbuf = \"\";\n    int ret, data_len = 0;\n    log.debug(\"正在分片拉取媒体文件 sdkFileId为{}\", sdkfileid);\n    while (true) {\n      long mediaData = Finance.NewMediaData();\n      ret = Finance.GetMediaData(sdk, indexbuf, sdkfileid, proxy, passwd, timeout, mediaData);\n      if (ret != 0) {\n        Finance.FreeMediaData(mediaData);\n        throw new WxErrorException(\"getmediadata err ret \" + ret);\n      }\n\n      data_len += Finance.GetDataLen(mediaData);\n      log.debug(\"正在分片拉取媒体文件 len:{}, data_len:{}, is_finish:{} \\n\", Finance.GetIndexLen(mediaData), data_len, Finance.IsMediaDataFinish(mediaData));\n\n      try {\n        // 大于512k的文件会分片拉取，此处需要使用追加写，避免后面的分片覆盖之前的数据。\n        action.accept(Finance.GetData(mediaData));\n      } catch (Exception e) {\n        log.error(\"处理媒体文件分片失败，sdkfileid={}\", sdkfileid, e);\n      }\n\n      if (Finance.IsMediaDataFinish(mediaData) == 1) {\n        // 已经拉取完成最后一个分片\n        Finance.FreeMediaData(mediaData);\n        break;\n      } else {\n        // 获取下次拉取需要使用的indexbuf","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/binarywang/WxJava/blob/1c43293a3c2c9d7e91304b6d037fb017f680d0c6/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java#L251-L287","documentation":"Thrown when Finance.GetMediaData() returns a non-zero code during chunked media-file download from the chat archive. This call fetches binary media (images, voice, video, files) identified by sdkfileid, optionally through a proxy. A non-zero return signals the native SDK could not retrieve the media chunk.","triggerScenarios":"Calling getMediaFile() with an sdkfileid that is expired (media is only downloadable for a limited time after the message), an uninitialized/stale SDK handle, an unreachable or misconfigured proxy, a network timeout shorter than the actual download time, or an sdkfileid from a different access_token session.","commonSituations":"Media files expire — attempting to download long after the chat message was archived; proxy credentials are wrong or the proxy host is unreachable; the timeout value is too low for large multi-chunk files; the SDK handle was closed or the process restarted losing the native context; sdkfileid was extracted from a re-fetched seq that no longer maps to valid media.","solutions":["Download media promptly after retrieving chat records — WeChat retains media files for a limited window only","If using a proxy, verify proxy host, port, and credentials (passwd parameter) are correct and reachable","Increase the timeout parameter to accommodate large files (each chunk is up to 512 KB, multi-GB files need many chunks)","Ensure the SDK handle is freshly initialized via getOrInitThreadLocalSdk() before the media download loop","Check the native return code: 10001/10002 indicate SDK or token problems, network-range codes indicate connectivity issues"],"exampleFix":"// before\nret = Finance.GetMediaData(sdk, indexbuf, sdkfileid, proxy, passwd, timeout, mediaData);\n\n// after — validate sdk handle and use generous timeout for large files\nif (sdk == 0) {\n  throw new WxErrorException(\"SDK 未初始化，无法下载媒体文件\");\n}\nlong effectiveTimeout = Math.max(timeout, 30000); // at least 30s per chunk\nret = Finance.GetMediaData(sdk, indexbuf, sdkfileid, proxy, passwd, effectiveTimeout, mediaData);\nif (ret != 0) {\n  log.warn(\"媒体下载失败 ret={}, sdkfileid={} (可能已过期)\", ret, sdkfileid);\n}","handlingStrategy":"try-catch","validationCode":"// Validate before media download\nif (sdk == 0) {\n  throw new IllegalStateException(\"SDK 未初始化\");\n}\nif (StringUtils.isBlank(sdkfileid)) {\n  throw new IllegalArgumentException(\"sdkfileid 不能为空\");\n}\n// Download media within a reasonable time window after fetching chat records","typeGuard":null,"tryCatchPattern":"try {\n  msgAuditService.getMediaFile(sdk, sdkfileid, proxy, passwd, 60000, targetPath);\n} catch (WxErrorException e) {\n  log.warn(\"媒体文件下载失败 sdkfileid={}: {}\", sdkfileid, e.getMessage());\n  // Media may have expired; skip and continue processing other records\n  if (e.getMessage().contains(\"err ret\")) {\n    log.warn(\"媒体可能已过期或网络不可达，跳过此文件\");\n  }\n}","preventionTips":["Process and download media files immediately after fetching chat records, before they expire","Implement a queue that downloads media with retry within the expiry window","Use a reliable proxy if your server cannot directly reach WeChat endpoints","Set a generous timeout for large media files (default 512KB chunks, files can be multi-MB)"],"tags":["wechat-cp","msg-audit","media-download","finance-sdk","native","network"],"backgroundTag":null,"analyzedSha":"1c43293a3c2c9d7e91304b6d037fb017f680d0c6","analyzedAt":"2026-08-14T02:29:11.060Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}