{"record":{"id":"987291c0e3bbe0b1","repo":"JeffreySu/WeiXinMPSDK","slug":"tenpayv3info-987291","errorCode":null,"errorMessage":"公钥序列号不存在！请查看日志！","messagePattern":"公钥序列号不存在！请查看日志！","errorType":"exception","errorClass":"TenpaySecurityException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/TenPayV3Info.cs","lineNumber":351,"sourceCode":"        public async Task<string> GetPublicKeyAsync(string serialNumber, ISenparcWeixinSettingForTenpayV3 tenpayV3Setting, CancellationToken cancellationToken)\n        {\n            var keys = await GetPublicKeysAsync(tenpayV3Setting, cancellationToken).ConfigureAwait(false);\n            if (keys.TryGetValue(serialNumber, out string publicKey))\n            {\n                return publicKey;\n            }\n\n            // 平台证书/公钥可能刚完成轮换；未命中时立即刷新一次，而不是等待常规缓存过期。\n            keys = await RefreshPublicKeysAfterMissAsync(keys, tenpayV3Setting, cancellationToken).ConfigureAwait(false);\n            if (keys != null && keys.TryGetValue(serialNumber, out publicKey))\n            {\n                return publicKey;\n            }\n\n            // 日志仅记录定位所需标识，禁止序列化整个对象（其中包含私钥、APIv3 Key 等敏感信息）。\n            SenparcTrace.BaseExceptionLog(new TenpaySecurityException(\n                $\"公钥序列号不存在！serialNumber:{serialNumber},MchId:{MchId},SubMchId:{Sub_MchId}\"));\n            throw new TenpaySecurityException(\"公钥序列号不存在！请查看日志！\", true);\n        }\n    }\n}\n","sourceCodeStart":333,"sourceCodeEnd":355,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/TenPayV3Info.cs#L333-L355","documentation":"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 '公钥序列号不存在！请查看日志！'.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nvar key = await info.GetPublicKeyAsync(\"OLD-SERIAL\"); // throws\n// after\nawait info.RefreshPublicKeysAsync(); // re-sync keys from WeChat Pay\nvar key = await info.GetPublicKeyAsync(serialFromHeader);","handlingStrategy":"try-catch","validationCode":"if (!await publicKeyCache.ContainsSerialAsync(serialNumber))\n    await publicKeyCache.RefreshFromWeChatPayAsync(); // fetch before use","typeGuard":null,"tryCatchPattern":"try { var key = await info.GetPublicKeyAsync(serial); }\ncatch (TenpaySecurityException ex)\n{ logger.LogWarning(ex, \"Unknown public key serial {Serial}\", serial); await info.RefreshPublicKeysAsync(); /* retry once */ }","preventionTips":["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."],"tags":["wechat-pay","public-key","cache","security"],"backgroundTag":"record-not-found","analyzedSha":"be573f6f94bdbf718dd5f6cdecb137fbc7ff651e","analyzedAt":"2026-09-12T10:01:50.733Z","contentChangedAt":"2026-09-12T10:01:50.733Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}