JeffreySu/WeiXinMPSDK · error · ArgumentException

目标流必须可写。

Error message

目标流必须可写。

What it means

DownloadMedia writes raw media chunks into the destination stream, so the stream must support writing. If destination.CanWrite is false (e.g. a read-only stream), the library throws ArgumentException with message '目标流必须可写。' before starting the download.

Solutions

  1. Open the destination stream with write access, e.g. new FileStream(path, FileMode.Create, FileAccess.Write)
  2. Use a MemoryStream if you just need the bytes in memory
  3. Assert destination.CanWrite before calling DownloadMedia and choose an appropriate stream type

Example fix

// before
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
client.DownloadMedia(sdkFileId, fs);
// after
using var fs = new FileStream(path, FileMode.Create, FileAccess.Write);
client.DownloadMedia(sdkFileId, fs);
Defensive patterns

Strategy: validation

Validate before calling

if (stream is null || !stream.CanWrite) throw new ArgumentException("destination stream must be writable", nameof(stream));

Type guard

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

Try / catch

try { client.DownloadMedia(sdkFileId, stream); }
catch (ArgumentException ex) when (ex.ParamName == "destination") { /* reopen stream with FileAccess.Write */ }

Prevention

When it happens

Trigger: Calling DownloadMedia with a Stream whose CanWrite returns false — for example a FileStream opened with FileAccess.Read, Stream.Null, or a stream wrapped in a read-only wrapper.

Common situations: Opening a FileStream with FileMode.Open/FileAccess.Read for inspection instead of writing, passing a stream obtained from a read-only HTTP response, or reusing a stream that was closed (a disposed MemoryStream reports CanWrite=false).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

        /// <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);
                }

                if (chunk.is_finished)
                {
                    return totalBytes;
                }

View on GitHub (pinned to be573f6f94)