JeffreySu/WeiXinMPSDK · error · ArgumentException

品牌 API 鉴权参数不能为空。

Error message

品牌 API 鉴权参数不能为空。

What it means

TenPayBrandApiCredentials.RequireValue validates every constructor parameter (merchant ID, serial, keys, etc.) and throws ArgumentException when a value is null, empty, or whitespace. The constructor refuses to build brand API credentials with missing authentication material.

Solutions

  1. Check the specific parameterName in the ArgumentException message to identify which field is missing.
  2. Verify the config source (appsettings.json, env var, key vault) actually contains the value in the deployed environment.
  3. Validate all credential strings with string.IsNullOrWhiteSpace before constructing the credentials object.
  4. If credentials are optional, only construct TenPayBrandApiCredentials when all values are present.

Example fix

// before
var creds = new TenPayBrandApiCredentials(config["MchId"], config["Serial"], config["PublicKey"], config["PrivateKey"]); // values may be null
// after
var mchId = config["MchId"] ?? throw new InvalidOperationException("MchId not configured");
var serial = config["Serial"] ?? throw new InvalidOperationException("Serial not configured");
var publicKey = config["PublicKey"] ?? throw new InvalidOperationException("PublicKey not configured");
var privateKey = config["PrivateKey"] ?? throw new InvalidOperationException("PrivateKey not configured");
var creds = new TenPayBrandApiCredentials(mchId, serial, publicKey, privateKey);
Defensive patterns

Strategy: validation

Validate before calling

string Require(string? v, string name) =>
    string.IsNullOrWhiteSpace(v) ? throw new InvalidOperationException($"{name} is not configured.") : v;
var creds = new TenPayBrandApiCredentials(Require(cfg["MchId"],"MchId"), Require(cfg["Serial"],"Serial"), Require(cfg["PublicKey"],"PublicKey"), Require(cfg["PrivateKey"],"PrivateKey"));

Type guard

bool HasBrandConfig(ISenparcWeixinSettingForTenpayV3 s) =>
    !string.IsNullOrWhiteSpace(s?.TenPayV3_MchId) && !string.IsNullOrWhiteSpace(s?.TenPayV3_Key);

Try / catch

try { creds = new TenPayBrandApiCredentials(mchId, serial, publicKey, privateKey); }
catch (ArgumentException ex) { logger.LogError(ex, "Missing brand credential: {Param}", ex.ParamName); throw; }

Prevention

When it happens

Trigger: Constructing TenPayBrandApiCredentials with null/empty/whitespace for any required string parameter — e.g. reading mchId or publicKey from configuration that returned empty, or a variable not yet initialized.

Common situations: Missing appsettings entries for brand API keys; environment variable not set in the deployment environment; secrets not loaded from the key vault; accidentally passing the wrong variable (null).

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/HttpHandlers/TenPayBrandApiCredentials.cs:92

        /// 品牌 API 证书对应的 PKCS#8 RSA 私钥 Base64 DER。
        /// </summary>
        public string BrandPrivateKey { get; }

        /// <summary>
        /// 品牌 ID 关联的微信支付公钥 ID。
        /// </summary>
        public string WechatpayPublicKeyId { get; }

        /// <summary>
        /// 用于校验品牌 API 响应签名的微信支付公钥 Base64 DER。
        /// </summary>
        public string WechatpayPublicKey { get; }

        private static string RequireValue(string value, string parameterName)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentException("品牌 API 鉴权参数不能为空。",
                    parameterName);
            }

            return value;
        }

        private static string NormalizeKey(string value, string parameterName)
        {
            var requiredValue = RequireValue(value, parameterName);
            var builder = new StringBuilder();
            using (var reader = new StringReader(requiredValue))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    var trimmedLine = line.Trim();
                    if (trimmedLine.StartsWith("-----",
                        StringComparison.Ordinal))

View on GitHub (pinned to be573f6f94)