JeffreySu/WeiXinMPSDK · warning · ArgumentException
开放硬件回调正文必须包含非空 encrypt 字段。
Error message
开放硬件回调正文必须包含非空 encrypt 字段。
What it means
OpenHardwareCallbackHandler.DecryptAndParse deserializes the callback body into OpenHardwareEncryptedCallbackRequest and requires a non-empty encrypt field, which holds the AES-encrypted payload. If the JSON body is null, unparseable, or lacks/empties 'encrypt', it throws ArgumentException so callers know the callback is malformed and cannot be decrypted.
Solutions
- Inspect the raw body: if it is the URL-verification handshake (GET with msg_signature/echostr), handle it via the verify path instead of DecryptAndParse.
- Guard with a quick check before calling: body contains a non-empty "encrypt" field.
- Return 400 for bodies without 'encrypt' so WeChat Work's console shows the misconfiguration.
- Confirm the callback URL configured in the WeChat Work admin console points to the correct handler.
Example fix
// before
var result = handler.DecryptAndParse(body, token, aesKey, receiveId); // throws if encrypt missing
// after
if (string.IsNullOrWhiteSpace(body)) return Results.BadRequest("empty body");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.TryGetProperty("encrypt", out var enc) || string.IsNullOrWhiteSpace(enc.GetString()))
return Results.BadRequest("missing encrypt field");
var result = handler.DecryptAndParse(body, token, aesKey, receiveId); Defensive patterns
Strategy: validation
Validate before calling
using var doc = JsonDocument.Parse(body);
bool hasEncrypt = doc.RootElement.ValueKind == JsonValueKind.Object
&& doc.RootElement.TryGetProperty("encrypt", out var e)
&& !string.IsNullOrWhiteSpace(e.GetString());
if (!hasEncrypt) return Results.BadRequest("missing encrypt field"); Type guard
static bool TryGetEncrypt(string body, out string encrypt)
{
encrypt = null;
try { var o = JsonConvert.DeserializeObject<OpenHardwareEncryptedCallbackRequest>(body); encrypt = o?.encrypt; }
catch (JsonException) { }
return !string.IsNullOrWhiteSpace(encrypt);
} Try / catch
try { var result = handler.DecryptAndParse(body, token, aesKey, receiveId); }
catch (ArgumentException ex) { logger.LogWarning(ex, "Malformed open-hardware callback"); return Results.BadRequest(); } Prevention
- Route GET URL-verification handshakes to a separate handler.
- Reject empty/non-JSON bodies early with 400.
- Verify the callback URL configured in the WeChat Work console matches this endpoint.
When it happens
Trigger: WeChat Work posts a callback whose body is not the expected {"encrypt":"..."} envelope — e.g. an empty GET-verification probe forwarded to this handler, an HTML error page body, or an attacker/fuzzer POSTing arbitrary JSON.
Common situations: Misconfigured callback URL receiving requests meant for another endpoint; load balancer error pages being passed through; verifying the URL handshake with a plaintext echo and mistakenly calling DecryptAndParse on it.
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/1caaa5b85678c0b0.
Report an issue: GitHub.
Appendix: source
Thrown at src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/OpenHardware/OpenHardwareCallbackHandler.cs:59
/// <exception cref="OpenHardwareCallbackCryptException">验签、解密或接收方校验失败时抛出。</exception>
public static OpenHardwareCallbackParseResult DecryptAndParse(
string token, string encodingAesKey, string receiveId,
string msgSignature, string timestamp, string nonce,
string encryptedBody)
{
EnsureNotEmpty(token, nameof(token));
EnsureNotEmpty(encodingAesKey, nameof(encodingAesKey));
EnsureNotEmpty(receiveId, nameof(receiveId));
EnsureNotEmpty(msgSignature, nameof(msgSignature));
EnsureNotEmpty(timestamp, nameof(timestamp));
EnsureNotEmpty(nonce, nameof(nonce));
EnsureNotEmpty(encryptedBody, nameof(encryptedBody));
var envelope = JsonConvert
.DeserializeObject<OpenHardwareEncryptedCallbackRequest>(encryptedBody);
if (envelope == null || string.IsNullOrWhiteSpace(envelope.encrypt))
{
throw new ArgumentException(
"开放硬件回调正文必须包含非空 encrypt 字段。",
nameof(encryptedBody));
}
var plaintext = string.Empty;
var crypt = new WXBizMsgCrypt(token, encodingAesKey, receiveId);
var errorCode = crypt.DecryptJsonMsg(msgSignature, timestamp, nonce,
envelope.encrypt, ref plaintext);
if (errorCode != 0)
{
throw new OpenHardwareCallbackCryptException(errorCode);
}
return new OpenHardwareCallbackParseResult
{
tousername = envelope.tousername,
plaintext = plaintext,
message = ParsePlaintext(plaintext)View on GitHub (pinned to be573f6f94)