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
- Open the destination stream with write access, e.g. new FileStream(path, FileMode.Create, FileAccess.Write)
- Use a MemoryStream if you just need the bytes in memory
- 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
- Open FileStreams with FileMode.Create/FileAccess.Write for downloads
- Remember disposed streams report CanWrite=false — check IsDisposed/CanWrite
- Unit-test download paths with the exact stream type used in production
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
- ArgumentNullException (destination is null)
- Finance SDK 尚未完成媒体下载,但没有返回可继续使用的新索引缓冲区。
- ArgumentNullException (options is null)
- 原生 SDK 网络请求超时时间必须大于 0 秒。
- 参数不能为空。
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)