JeffreySu/WeiXinMPSDK · error · TenpaySecurityException
公钥序列号不存在!请查看日志!
Error message
公钥序列号不存在!请查看日志!
What it means
TenPayV3Info.GetPublicKeyAsync looks up the public key registered for the given serialNumber in the local key cache; if no entry matches, it first logs a TenpaySecurityException with the serial and merchant IDs (deliberately excluding secrets) and then throws TenpaySecurityException '公钥序列号不存在!请查看日志!'.
Solutions
- Check the log line for the exact serialNumber/MchId and refresh the public key list from WeChat Pay (merchant platform or API), then retry.
- Enable/confirm public key mode (TenPayV3_TenPayPubKeyEnable) and ensure the 微信支付公钥 is configured and loaded at startup.
- Add fallback logic to fetch and cache keys on unknown serials instead of failing permanently.
- Verify you are not mixing key material across merchant accounts (MchId/SubMchId).
Example fix
// before
var key = await info.GetPublicKeyAsync("OLD-SERIAL"); // throws
// after
await info.RefreshPublicKeysAsync(); // re-sync keys from WeChat Pay
var key = await info.GetPublicKeyAsync(serialFromHeader); Defensive patterns
Strategy: try-catch
Validate before calling
if (!await publicKeyCache.ContainsSerialAsync(serialNumber))
await publicKeyCache.RefreshFromWeChatPayAsync(); // fetch before use Try / catch
try { var key = await info.GetPublicKeyAsync(serial); }
catch (TenpaySecurityException ex)
{ logger.LogWarning(ex, "Unknown public key serial {Serial}", serial); await info.RefreshPublicKeysAsync(); /* retry once */ } Prevention
- Load/refresh WeChat Pay public keys at startup and on unknown-serial failures.
- Subscribe to WeChat Pay key-rotation notices and update config promptly.
- Keep key caches per merchant account to avoid cross-tenant serial mismatches.
When it happens
Trigger: Verifying a request/response whose Wechatpay-Serial refers to a public key version that was never downloaded/registered locally — e.g. right after WeChat Pay rotated keys, or before the first successful key fetch.
Common situations: WeChat Pay published a new public key and callbacks now arrive with the new serial; app restarted and the key cache is cold; multi-tenant setup where the key belongs to a different MchId/SubMchId; public-key mode not enabled (TenPayV3_TenPayPubKeyEnable) so keys were never populated.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- RequestAsync 签名验证失败:
- 缓存策略 不支持枚举,请先检查 GetCapabilities()。
- WeixinPayInfoCollection尚未注册Partner:
- TenPayV3InfoCollection尚未注册Mch:
- 没有设置证书加密类型(EncryptionType)
AI-assisted analysis of JeffreySu/WeiXinMPSDK@be573f6f94 (2026-09-12).
Data as JSON: /api/errors/987291c0e3bbe0b1.
Report an issue: GitHub.
Appendix: source
Thrown at src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/TenPayV3Info.cs:351
public async Task<string> GetPublicKeyAsync(string serialNumber, ISenparcWeixinSettingForTenpayV3 tenpayV3Setting, CancellationToken cancellationToken)
{
var keys = await GetPublicKeysAsync(tenpayV3Setting, cancellationToken).ConfigureAwait(false);
if (keys.TryGetValue(serialNumber, out string publicKey))
{
return publicKey;
}
// 平台证书/公钥可能刚完成轮换;未命中时立即刷新一次,而不是等待常规缓存过期。
keys = await RefreshPublicKeysAfterMissAsync(keys, tenpayV3Setting, cancellationToken).ConfigureAwait(false);
if (keys != null && keys.TryGetValue(serialNumber, out publicKey))
{
return publicKey;
}
// 日志仅记录定位所需标识,禁止序列化整个对象(其中包含私钥、APIv3 Key 等敏感信息)。
SenparcTrace.BaseExceptionLog(new TenpaySecurityException(
$"公钥序列号不存在!serialNumber:{serialNumber},MchId:{MchId},SubMchId:{Sub_MchId}"));
throw new TenpaySecurityException("公钥序列号不存在!请查看日志!", true);
}
}
}
View on GitHub (pinned to be573f6f94)