JeffreySu/WeiXinMPSDK · error · ArgumentNullException

ArgumentNullException (destination is null)

Error message

ArgumentNullException (destination is null)

What it means

DownloadMedia validates that the destination Stream is non-null before writing downloaded media chunks into it. Passing null means there is nowhere to write the media bytes, so the library fails fast with ArgumentNullException naming the 'destination' parameter instead of throwing a deeper NullReferenceException mid-download.

Solutions

  1. Create and pass a writable Stream (e.g. new FileStream(path, FileMode.Create) or new MemoryStream()) as the second argument
  2. Check the stream for null before calling DownloadMedia
  3. Verify no code path assigns null to the stream variable between creation and the call

Example fix

// before
Stream target = GetStreamOrNull();
long n = client.DownloadMedia(sdkFileId, target);
// after
using Stream target = GetStreamOrNull() ?? throw new InvalidOperationException("media stream not initialized");
long n = client.DownloadMedia(sdkFileId, target);
Defensive patterns

Strategy: validation

Validate before calling

if (destination == null) throw new ArgumentNullException(nameof(destination));
if (destination is null) { /* create or obtain a writable stream */ destination = new MemoryStream(); }

Type guard

bool HasWritableStream(Stream? s) => s is { CanWrite: true };

Try / catch

try { client.DownloadMedia(sdkFileId, stream); }
catch (ArgumentNullException ex) when (ex.ParamName == "destination") { /* initialize stream and retry */ }

Prevention

When it happens

Trigger: Calling MsgAuditFinanceClient.DownloadMedia(sdkFileId, destination) with a null destination Stream, e.g. a stream variable that was never initialized or a method that conditionally returns null.

Common situations: Developers wiring the stream from a config/file-open call that returned null, refactoring code so the stream creation was removed, or calling DownloadMedia before setting up a FileStream/MemoryStream.

Related errors


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

Appendix: source

Thrown at src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/MsgAudit/MsgAuditFinanceClient.cs:205

        /// <summary>
        /// 连续下载会话媒体文件的全部分片并写入目标流。
        /// </summary>
        /// <param name="sdkFileId">解密后消息 JSON 中的 <c>sdkfileid</c>。</param>
        /// <param name="destination">可写的目标流;本方法不会关闭该流。</param>
        /// <param name="cancellationToken">在每个原生分片请求前检查的取消令牌。</param>
        /// <returns>写入目标流的总字节数。</returns>
        /// <exception cref="ArgumentNullException"><paramref name="destination"/> 为空。</exception>
        /// <exception cref="ArgumentException"><paramref name="sdkFileId"/> 为空。</exception>
        /// <exception cref="ArgumentException"><paramref name="destination"/> 不可写。</exception>
        /// <exception cref="InvalidDataException">原生 SDK 未完成下载但没有返回可继续使用的新索引。</exception>
        public long DownloadMedia(string sdkFileId, Stream destination,
            CancellationToken cancellationToken = default)
        {
            ValidateRequiredText(sdkFileId, nameof(sdkFileId));
            if (destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }

            if (!destination.CanWrite)
            {
                throw new ArgumentException("目标流必须可写。", nameof(destination));
            }

            var indexBuffer = string.Empty;
            long totalBytes = 0;
            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var chunk = GetMediaData(sdkFileId, indexBuffer);
                if (chunk.data.Length > 0)
                {
                    destination.Write(chunk.data, 0, chunk.data.Length);
                    totalBytes = checked(totalBytes + chunk.data.LongLength);
                }

View on GitHub (pinned to be573f6f94)