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
- Check the specific parameterName in the ArgumentException message to identify which field is missing.
- Verify the config source (appsettings.json, env var, key vault) actually contains the value in the deployed environment.
- Validate all credential strings with string.IsNullOrWhiteSpace before constructing the credentials object.
- 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
- Fail fast at startup: validate all credential config in app bootstrap.
- Use ex.ParamName to identify the missing field.
- Ensure secrets are present in every deployment environment (CI, staging, prod).
- Never pass possibly-null config indexer results directly into constructors.
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)