binarywang/WxJava · error · WxErrorException
msg err ret {}
Error message
msg err ret {} What it means
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.
Source
Thrown at weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java:213
public String decryptChatData(long sdk, WxCpChatDatas.WxCpChatData chatData, Integer pkcs1) throws Exception {
// 企业获取的会话内容,使用企业自行配置的消息加密公钥进行加密,企业可用自行保存的私钥解开会话内容数据。
// msgAuditPriKey 会话存档私钥不能为空
String priKey = cpService.getWxCpConfigStorage().getMsgAuditPriKey();
if (StringUtils.isEmpty(priKey)) {
throw new WxErrorException("请配置会话存档私钥【msgAuditPriKey】");
}
String decryptByPriKey = WxCpCryptUtil.decryptPriKey(chatData.getEncryptRandomKey(), priKey, pkcs1);
// 每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。
long msg = Finance.NewSlice();
// 解密会话存档内容
// sdk不会要求用户传入rsa私钥,保证用户会话存档数据只有自己能够解密。
// 此处需要用户先用rsa私钥解密encrypt_random_key后,作为encrypt_key参数传入sdk来解密encrypt_chat_msg获取会话存档明文。
int ret = Finance.DecryptData(sdk, decryptByPriKey, chatData.getEncryptChatMsg(), msg);
if (ret != 0) {
Finance.FreeSlice(msg);
throw new WxErrorException("msg err ret " + ret);
}
// 明文
String plainText = Finance.GetContentFromSlice(msg);
Finance.FreeSlice(msg);
return plainText;
}
@Override
public String getChatPlainText(@NonNull long sdk, WxCpChatDatas.@NonNull WxCpChatData chatData,
@NonNull Integer pkcs1) throws Exception {
return this.decryptChatData(sdk, chatData, pkcs1);
}
@Override
public void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String proxy, String passwd,
@NonNull long timeout, @NonNull String targetFilePath) throws WxErrorException {
/**View on GitHub (pinned to 1c43293a3c)
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
Example fix
// before
String priKey = configStorage.getMsgAuditPriKey(); // possibly wrong or unformatted
String decryptKey = WxCpCryptUtil.decryptPriKey(chatData.getEncryptRandomKey(), priKey, pkcs1);
int ret = Finance.DecryptData(sdk, decryptKey, chatData.getEncryptChatMsg(), msg);
// after — validate key presence and format before calling DecryptData
String priKey = configStorage.getMsgAuditPriKey();
if (StringUtils.isBlank(priKey) || !priKey.contains("-----BEGIN")) {
throw new WxErrorException("msgAuditPriKey 格式不正确,应为含 PEM 头的 RSA 私钥");
}
// ensure pkcs1 matches the actual key format
int ret = Finance.DecryptData(sdk, decryptKey, chatData.getEncryptChatMsg(), msg);
if (ret != 0) {
log.error("DecryptData 失败 ret={}, 可能是私钥不匹配或 SDK token 过期", ret);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate private key and SDK handle before decrypting
String priKey = configStorage.getMsgAuditPriKey();
if (StringUtils.isBlank(priKey)) {
throw new IllegalStateException("msgAuditPriKey 未配置,无法解密会话存档");
}
if (!priKey.contains("PRIVATE KEY")) {
throw new IllegalStateException("msgAuditPriKey 格式不正确,应为 PEM 格式 RSA 私钥");
}
if (sdk == 0) {
throw new IllegalStateException("SDK 句柄无效,请重新初始化");
} Try / catch
try {
String plaintext = msgAuditService.decryptChatData(sdk, chatData, pkcs1);
} catch (WxErrorException e) {
log.error("会话存档解密失败: {}", e.getMessage());
// ret=1 typically means key mismatch; re-init SDK or verify RSA key pair
if (e.getMessage().contains("ret 1")) {
log.error("疑似 RSA 私钥与公钥不匹配,请检查企业微信管理后台配置");
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- getmediadata err ret {}
- getchatdata err ret + ret
- getchatdata err ret {}
- 请配置会话存档sdk文件的路径,不要配错了!!
- 请仔细配置会话存档文件路径!!
AI-assisted analysis of binarywang/WxJava@1c43293a3c (2026-08-14).
Data as JSON: /api/errors/b2c54af5d36175ae.
Report an issue: GitHub.