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

  1. 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.
  2. Guard with a quick check before calling: body contains a non-empty "encrypt" field.
  3. Return 400 for bodies without 'encrypt' so WeChat Work's console shows the misconfiguration.
  4. 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

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)