{"record":{"id":"b2c54af5d36175ae","repo":"binarywang/WxJava","slug":"msg-err-ret","errorCode":null,"errorMessage":"msg err ret {}","messagePattern":"msg 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":213,"sourceCode":"  public String decryptChatData(long sdk, WxCpChatDatas.WxCpChatData chatData, Integer pkcs1) throws Exception {\n    // 企业获取的会话内容，使用企业自行配置的消息加密公钥进行加密，企业可用自行保存的私钥解开会话内容数据。\n    // msgAuditPriKey 会话存档私钥不能为空\n    String priKey = cpService.getWxCpConfigStorage().getMsgAuditPriKey();\n    if (StringUtils.isEmpty(priKey)) {\n      throw new WxErrorException(\"请配置会话存档私钥【msgAuditPriKey】\");\n    }\n\n    String decryptByPriKey = WxCpCryptUtil.decryptPriKey(chatData.getEncryptRandomKey(), priKey, pkcs1);\n    // 每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice，在使用完slice中数据后，还需要调用FreeSlice释放。\n    long msg = Finance.NewSlice();\n\n    // 解密会话存档内容\n    // sdk不会要求用户传入rsa私钥，保证用户会话存档数据只有自己能够解密。\n    // 此处需要用户先用rsa私钥解密encrypt_random_key后，作为encrypt_key参数传入sdk来解密encrypt_chat_msg获取会话存档明文。\n    int ret = Finance.DecryptData(sdk, decryptByPriKey, chatData.getEncryptChatMsg(), msg);\n    if (ret != 0) {\n      Finance.FreeSlice(msg);\n      throw new WxErrorException(\"msg err ret \" + ret);\n    }\n\n    // 明文\n    String plainText = Finance.GetContentFromSlice(msg);\n    Finance.FreeSlice(msg);\n    return plainText;\n  }\n\n  @Override\n  public String getChatPlainText(@NonNull long sdk, WxCpChatDatas.@NonNull WxCpChatData chatData,\n                                 @NonNull Integer pkcs1) throws Exception {\n    return this.decryptChatData(sdk, chatData, pkcs1);\n  }\n\n  @Override\n  public void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String proxy, String passwd,\n                           @NonNull long timeout, @NonNull String targetFilePath) throws WxErrorException {\n    /**","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/binarywang/WxJava/blob/1c43293a3c2c9d7e91304b6d037fb017f680d0c6/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java#L195-L231","documentation":"Thrown when the native WeChat Finance SDK's Finance.DecryptData() returns a non-zero code while decrypting chat-archive ciphertext. The SDK takes an encrypt_key (obtained by RSA-decrypting encrypt_random_key with your private key) and uses it to decrypt encrypt_chat_msg into plaintext. A non-zero return means the decryption step itself failed inside the C library.","triggerScenarios":"Calling decryptChatData() or getChatPlainText() / getDecryptData() after getChatRecords(). The Finance.DecryptData call returns non-zero when the RSA-derived encrypt_key is wrong, the private key (msgAuditPriKey) does not match the public key configured in the WeChat admin console, the SDK handle (sdk) is stale/uninitialized, or encrypt_chat_msg payload is truncated/corrupted.","commonSituations":"Wrong RSA key pair (used the public key instead of the private key, or a key from a different corp), key format mismatch (PKCS#1 vs PKCS#8), the msgAuditPriKey was set without the proper PEM header/footer, the SDK was initialized with Finance.NewSdk() but the access token expired and was not refreshed, or the chatData seq/limit returned stale data from a different session.","solutions":["Verify that msgAuditPriKey matches the RSA private key paired with the public key uploaded to the WeChat Work admin console under 会话存档 settings","Ensure the pkcs1 parameter matches your key encoding (1 for PKCS#1, 8 for PKCS#8) and that the key string includes correct PEM boundaries","Re-initialize the SDK handle via getOrInitThreadLocalSdk() if the access_token may have expired, then re-fetch chat records with the correct seq","Check the native return code value: code 1 typically indicates wrong key/params, code 10001/10002 indicate SDK initialization or token issues","Confirm the chatData object came from a fresh getChatRecords() call and its encryptRandomKey / encryptChatMsg fields are intact"],"exampleFix":"// before\nString priKey = configStorage.getMsgAuditPriKey(); // possibly wrong or unformatted\nString decryptKey = WxCpCryptUtil.decryptPriKey(chatData.getEncryptRandomKey(), priKey, pkcs1);\nint ret = Finance.DecryptData(sdk, decryptKey, chatData.getEncryptChatMsg(), msg);\n\n// after — validate key presence and format before calling DecryptData\nString priKey = configStorage.getMsgAuditPriKey();\nif (StringUtils.isBlank(priKey) || !priKey.contains(\"-----BEGIN\")) {\n  throw new WxErrorException(\"msgAuditPriKey 格式不正确，应为含 PEM 头的 RSA 私钥\");\n}\n// ensure pkcs1 matches the actual key format\nint ret = Finance.DecryptData(sdk, decryptKey, chatData.getEncryptChatMsg(), msg);\nif (ret != 0) {\n  log.error(\"DecryptData 失败 ret={}, 可能是私钥不匹配或 SDK token 过期\", ret);\n}","handlingStrategy":"try-catch","validationCode":"// Validate private key and SDK handle before decrypting\nString priKey = configStorage.getMsgAuditPriKey();\nif (StringUtils.isBlank(priKey)) {\n  throw new IllegalStateException(\"msgAuditPriKey 未配置，无法解密会话存档\");\n}\nif (!priKey.contains(\"PRIVATE KEY\")) {\n  throw new IllegalStateException(\"msgAuditPriKey 格式不正确，应为 PEM 格式 RSA 私钥\");\n}\nif (sdk == 0) {\n  throw new IllegalStateException(\"SDK 句柄无效，请重新初始化\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  String plaintext = msgAuditService.decryptChatData(sdk, chatData, pkcs1);\n} catch (WxErrorException e) {\n  log.error(\"会话存档解密失败: {}\", e.getMessage());\n  // ret=1 typically means key mismatch; re-init SDK or verify RSA key pair\n  if (e.getMessage().contains(\"ret 1\")) {\n    log.error(\"疑似 RSA 私钥与公钥不匹配，请检查企业微信管理后台配置\");\n  }\n  throw e;\n}","preventionTips":["Store the RSA private key as an environment variable or secret manager entry, not hardcoded","Verify the key pair by decrypting a known test record during application startup","Match the pkcs1 parameter to your key's actual encoding (check PEM header: BEGIN RSA KEY = PKCS#1, BEGIN PRIVATE KEY = PKCS#8)","Initialize the SDK handle once per thread and refresh the access_token proactively before expiry"],"tags":["wechat-cp","msg-audit","decryption","rsa","finance-sdk","native"],"backgroundTag":null,"analyzedSha":"1c43293a3c2c9d7e91304b6d037fb017f680d0c6","analyzedAt":"2026-08-14T02:29:11.060Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}