{"record":{"id":"2494ea94f5640d3c","repo":"JeffreySu/WeiXinMPSDK","slug":"argumentnullexception-value-is-null","errorCode":null,"errorMessage":"ArgumentNullException (value is null)","messagePattern":"ArgumentNullException \\(value is null\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/MsgAudit/MsgAuditFinanceNativeApi.cs","lineNumber":564,"sourceCode":"        }\n    }\n\n    /// <summary>\n    /// 将托管字符串转换为以空字符结尾的 UTF-8 原生缓冲区，并在释放时清零。\n    /// </summary>\n    internal sealed class Utf8NativeString : IDisposable\n    {\n        private readonly int _length;\n\n        /// <summary>\n        /// 创建 UTF-8 原生字符串。\n        /// </summary>\n        /// <param name=\"value\">待转换的托管字符串。</param>\n        public Utf8NativeString(string value)\n        {\n            if (value == null)\n            {\n                throw new ArgumentNullException(nameof(value));\n            }\n\n            var bytes = Encoding.UTF8.GetBytes(value);\n            _length = bytes.Length + 1;\n            Pointer = Marshal.AllocHGlobal(_length);\n            try\n            {\n                if (bytes.Length > 0)\n                {\n                    Marshal.Copy(bytes, 0, Pointer, bytes.Length);\n                }\n\n                Marshal.WriteByte(Pointer, bytes.Length, 0);\n            }\n            catch\n            {\n                Marshal.FreeHGlobal(Pointer);\n                Pointer = IntPtr.Zero;","sourceCodeStart":546,"sourceCodeEnd":582,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/MsgAudit/MsgAuditFinanceNativeApi.cs#L546-L582","documentation":"Utf8NativeString wraps a managed string into a null-terminated UTF-8 buffer for native calls, and its constructor rejects null input with ArgumentNullException(nameof(value)). You must pass an actual string (use string.Empty if you mean an empty value).","triggerScenarios":"Passing a null string to new Utf8NativeString(value) — e.g. corpId or secret variables that were null because config values were not loaded before constructing native API arguments.","commonSituations":"Missing appsettings entries for CorpId/Secret so the variable is null at call time; refactoring that renamed a config property and left the argument null.","solutions":["Null-check config values before constructing Utf8NativeString.","Coalesce to string.Empty only if the SDK accepts empty values; otherwise fail fast with a clear config error.","Load configuration before initializing the finance API (fail at startup, not per call)."],"exampleFix":"// before\nusing var corpId = new Utf8NativeString(config.CorpId); // ArgumentNullException if null\n// after\nif (string.IsNullOrEmpty(config.CorpId))\n    throw new InvalidOperationException(\"CorpId is not configured\");\nusing var corpId = new Utf8NativeString(config.CorpId);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrEmpty(config.CorpId) || string.IsNullOrEmpty(config.Secret))\n    throw new InvalidOperationException(\"CorpId/Secret not configured for Finance SDK\");","typeGuard":"static bool HasText(string s) => !string.IsNullOrWhiteSpace(s);","tryCatchPattern":"try { using var s = new Utf8NativeString(value); }\ncatch (ArgumentNullException ex) { logger.LogError(ex, \"Null native string argument\"); throw new InvalidOperationException(\"Config value missing\", ex); }","preventionTips":["Validate all config values once at startup.","Use options validation (IOptions with ValidateDataAnnotations).","Never pass possibly-null settings directly into native wrappers."],"tags":["null-argument","native-interop"],"backgroundTag":"null-argument","analyzedSha":"be573f6f94bdbf718dd5f6cdecb137fbc7ff651e","analyzedAt":"2026-09-12T10:01:50.733Z","contentChangedAt":"2026-09-12T10:01:50.733Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}