JeffreySu/WeiXinMPSDK · critical · InvalidOperationException

品牌 API 响应的微信支付公钥 ID 与配置不匹配。

Error message

品牌 API 响应的微信支付公钥 ID 与配置不匹配。

What it means

When brand API credentials are configured, the multipart response's Wechatpay-Serial header is compared with _brandApiCredentials.WechatpayPublicKeyId using an ordinal comparison; on mismatch the library throws InvalidOperationException because the response could not be verified with the configured public key. This guards against MITM or misconfigured platform credentials.

Solutions

  1. Update WechatpayPublicKeyId in TenPayBrandApiCredentials to the current serial returned in the response's Wechatpay-Serial header.
  2. Confirm you are using brand API credentials only for brand API endpoints (non-brand endpoints use a different verification path).
  3. Re-download the current WeChat Pay platform public key and reconfigure both key and key ID.
  4. Log the response's serial value and compare it with your configured ID to spot the mismatch.

Example fix

// before
var creds = new TenPayBrandApiCredentials(mchId, serial: "PUB_KEY_ID_OLD", publicKeyPem, privateKey);
// after — use the serial from the latest Wechatpay-Serial header
var creds = new TenPayBrandApiCredentials(mchId, serial: "PUB_KEY_ID_0114xxxxxxxx", publicKeyPem, privateKey);
Defensive patterns

Strategy: try-catch

Validate before calling

// Compare expected serial with what the platform advertises before sending
var expectedSerial = brandCredentials.WechatpayPublicKeyId;
if (string.IsNullOrWhiteSpace(expectedSerial)) throw new InvalidOperationException("Brand public key ID not configured.");

Try / catch

try { /* multipart request */ }
catch (InvalidOperationException ex) when (ex.Message.Contains("公钥 ID"))
{
    logger.LogError(ex, "Brand key ID mismatch: configured={Expected}", brandCredentials.WechatpayPublicKeyId);
    throw; // rotate/refresh credentials before retrying
}

Prevention

When it happens

Trigger: RequestMultipart* call against a brand API endpoint where the response's Wechatpay-Serial differs from the configured WechatpayPublicKeyId (rotated key not updated in config, wrong public key ID configured, or environment mismatch).

Common situations: WeChat Pay rotated its platform public key and the app still holds the old ID; copying credentials from sandbox to production; typos or whitespace in the configured key ID.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of JeffreySu/WeiXinMPSDK@be573f6f94 (2026-09-12). Data as JSON: /api/errors/649cbb5703cce1a8. Report an issue: GitHub.

Appendix: source

Thrown at src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/HttpHandlers/TenPayApiRequest.cs:492

                    {
                        result = new T { VerifySignSuccess = true };
                    }
                    else
                    {
                        result = content.GetObject<T>();
                        if (checkSign)
                        {
                            var timestamp = responseMessage.Headers.GetValues("Wechatpay-Timestamp").First();
                            var nonce = responseMessage.Headers.GetValues("Wechatpay-Nonce").First();
                            var signature = responseMessage.Headers.GetValues("Wechatpay-Signature").First();
                            var serial = responseMessage.Headers.GetValues("Wechatpay-Serial").First();
                            if (_brandApiCredentials != null)
                            {
                                if (!string.Equals(serial,
                                    _brandApiCredentials.WechatpayPublicKeyId,
                                    StringComparison.Ordinal))
                                {
                                    throw new InvalidOperationException(
                                        "品牌 API 响应的微信支付公钥 ID 与配置不匹配。");
                                }

                                result.VerifySignSuccess =
                                    TenPaySignHelper.VerifyTenpaySign(
                                        CertType.RSA, timestamp, nonce,
                                        signature, content,
                                        _brandApiCredentials.WechatpayPublicKey,
                                        true);
                            }
                            else
                            {
                                var publicKey = await TenPayV3InfoCollection
                                    .GetAPIv3PublicKeyAsync(_tenpayV3Setting,
                                        serial, cancellationToken)
                                    .ConfigureAwait(false);

                                if (_tenpayV3Setting.EncryptionType == CertType.SM)

View on GitHub (pinned to be573f6f94)