JeffreySu/WeiXinMPSDK · error · ArgumentException
预签名请求必须同时提供 nonce_str 和 ts。
Error message
预签名请求必须同时提供 nonce_str 和 ts。
What it means
When a PayTool request already carries a signature (sig is non-empty), PrepareRequest requires the companion fields nonce_str and ts so the signature can be validated; it throws ArgumentException (预签名请求必须同时提供 nonce_str 和 ts。) if either nonce_str is empty or ts <= 0.
Solutions
- Set both request.nonce_str (random string) and request.ts (current Unix timestamp in seconds) whenever request.sig is provided
- If the request is not intentionally pre-signed, clear request.sig so PrepareRequest signs it using payToolApiSecret instead
- Check deserialization/binding so ts is correctly populated as a positive integer
Example fix
// before
req.sig = ComputeSig(req); // sig set, but nonce_str/ts empty
PayToolSignatureHelper.PrepareRequest(req, apiSecret);
// after
req.nonce_str = Guid.NewGuid().ToString("N");
req.ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
req.sig = ComputeSig(req);
PayToolSignatureHelper.PrepareRequest(req, apiSecret); Defensive patterns
Strategy: validation
Validate before calling
bool presignOk = string.IsNullOrEmpty(req.sig) || (!string.IsNullOrEmpty(req.nonce_str) && req.ts > 0);
if (!presignOk) throw new InvalidOperationException("Pre-signed requests need both nonce_str and ts"); Type guard
bool IsPreSigned(PayToolSignedRequestBase r) => !string.IsNullOrEmpty(r.sig); bool PreSignFieldsValid(PayToolSignedRequestBase r) => IsPreSigned(r) && !string.IsNullOrEmpty(r.nonce_str) && r.ts > 0;
Try / catch
try { PayToolSignatureHelper.PrepareRequest(req, apiSecret); }
catch (ArgumentException ex) when (ex.Message.Contains("nonce_str")) { logger.LogError(ex, "Pre-sign fields incomplete"); req.sig = null; PayToolSignatureHelper.PrepareRequest(req, apiSecret); } Prevention
- Always set nonce_str and ts (Unix seconds) together whenever you set sig manually
- Let PrepareRequest sign the request instead of hand-setting sig when possible
- Verify ts binding from JSON/form input is a positive integer, not a defaulted 0
When it happens
Trigger: Calling PrepareRequest on a request where request.sig is set but request.nonce_str is null/empty or request.ts is 0/negative — e.g. manually setting sig without filling nonce_str/ts, or deserializing a partially filled request.
Common situations: Reusing a request object across retries where nonce_str/ts were cleared; hand-crafting pre-signed requests in tests; binding from a form/JSON where ts was sent as a string and defaulted to 0; forgetting to set ts (Unix seconds) when supplying sig manually.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- ArgumentNullException (request is null)
- ArgumentNullException (response is null)
- OpenHardwareCallbackCryptException (encrypt failed…
- 参数不能为空。
- AppId 不能为空。
AI-assisted analysis of JeffreySu/WeiXinMPSDK@be573f6f94 (2026-09-12).
Data as JSON: /api/errors/7d10681551dd291d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/PayTool/PayToolSignatureHelper.cs:47
/// <summary>
/// 为收款工具请求补齐随机串、Unix 时间戳和数字签名。
/// 已提供签名时不会重新签名,并要求调用方同时提供原签名对应的随机串和时间戳。
/// </summary>
/// <param name="request">需要签名的收款工具请求。</param>
/// <param name="payToolApiSecret">收银台 API 调用密钥;请求未预签名时必填。</param>
public static void PrepareRequest(PayToolSignedRequestBase request,
string payToolApiSecret)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
if (!string.IsNullOrEmpty(request.sig))
{
if (string.IsNullOrEmpty(request.nonce_str) || request.ts <= 0)
{
throw new ArgumentException("预签名请求必须同时提供 nonce_str 和 ts。",
nameof(request));
}
return;
}
if (string.IsNullOrEmpty(payToolApiSecret))
{
throw new ArgumentException("请求未提供 sig 时必须提供收银台 API 调用密钥。",
nameof(payToolApiSecret));
}
if (string.IsNullOrEmpty(request.nonce_str))
{
request.nonce_str = Guid.NewGuid().ToString("N");
}
if (request.ts <= 0)View on GitHub (pinned to be573f6f94)