JeffreySu/WeiXinMPSDK · error · ArgumentNullException

data

Error message

data

What it means

RequireCustomsData is a private guard used by all synchronous and asynchronous customs APIs (DeclareOrder, DeclareQuery, Redeclare). It throws ArgumentNullException named 'data' when the caller passes a null request-data object, since the library cannot build a request without it.

Solutions

  1. Construct the appropriate CustomsRequestData instance before calling the customs API.
  2. Null-check the data object at the call site before invoking.
  3. Fix whatever factory/configuration step is producing null instead of a data object.

Example fix

// before
CustomsDeclareRequestData data = null;
await tenPayV3.CustomsDeclareOrderAsync(data);
// after
var data = new CustomsDeclareRequestData(key, appid, mchId, mchCustomsNo, outTradeNo, ...);
await tenPayV3.CustomsDeclareOrderAsync(data);
Defensive patterns

Strategy: type-guard

Validate before calling

// C#
if (data is null) throw new InvalidOperationException("Customs request data must be constructed before calling the API");

Type guard

bool IsUsable<T>(T obj) where T : class => obj is not null; // if (IsUsable(data)) await tenPayV3.CustomsDeclareOrderAsync(data);

Try / catch

try { await tenPayV3.CustomsDeclareOrderAsync(data); }
catch (ArgumentNullException ex) when (ex.ParamName == "data") { log.LogError("Customs data was null — construction failed earlier"); }

Prevention

When it happens

Trigger: Calling TenPayV3.CustomsDeclareOrder / CustomsDeclareOrderAsync / CustomsDeclareQuery / CustomsDeclareQueryAsync / CustomsRedeclare / CustomsRedeclareAsync with a null CustomsRequestDataBase instance.

Common situations: The request-data object was conditionally built (e.g. result of a factory method returning null when config was incomplete) or a variable was declared but never assigned before the API call.

Related errors


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

Appendix: source

Thrown at src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPay/V3/Universal/Customs/TenPayV3.Customs.cs:122

                GetCustomsUrl(CustomsRedeclarePath), data.ToXml(key), timeOut));
        }

        /// <summary>异步对支付订单重新进行海关申报。</summary>
        public static async Task<CustomsRedeclareResult> CustomsRedeclareAsync(
            CustomsRedeclareRequestData data, string key,
            int timeOut = Config.TIME_OUT)
        {
            RequireCustomsData(data);
            var xml = await PostCustomsAsync(GetCustomsUrl(CustomsRedeclarePath),
                data.ToXml(key), timeOut).ConfigureAwait(false);
            return new CustomsRedeclareResult(xml);
        }

        private static void RequireCustomsData(CustomsRequestDataBase data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
        }

        private static string GetCustomsUrl(string path)
        {
            return Senparc.Weixin.Config.TenPayV3Host.TrimEnd('/') + path;
        }

        private static string PostCustoms(string url, string xml, int timeOut)
        {
            var bytes = Encoding.UTF8.GetBytes(xml);
            using (var stream = new MemoryStream(bytes))
            {
                return RequestUtility.HttpPost(CommonDI.CommonSP, url, null,
                    stream, timeOut: timeOut);
            }
        }

View on GitHub (pinned to be573f6f94)