dotnet/wpf · error · ObjectDisposedException

SR.ByteRangeDownloaderDisposed

Error message

SR.ByteRangeDownloaderDisposed

What it means

ObjectDisposedException thrown by ByteRangeDownloader.CheckDisposed when any public operation (GetDownloadedByteRanges, RequestByteRanges, or the Proxy/Credentials/CachePolicy/FileMutex properties) is invoked after the downloader's Dispose path set _disposed to true.

Solutions

  1. Stop using the instance after Dispose; create a new ByteRangeDownloader if more downloads are needed
  2. Guard usage with a disposed flag or lock shared between dispose and use
  3. Fix ownership so only one component disposes the downloader

Example fix

// before
downloader.Dispose();
downloader.RequestByteRanges(ranges); // throws
// after
downloader.Dispose();
downloader = new ByteRangeDownloader(uri, handle, tempFile);
downloader.RequestByteRanges(ranges);
Defensive patterns

Strategy: try-catch

Validate before calling

// guard flag maintained by caller
bool usable = downloader != null && !disposed;
if (!usable) throw new InvalidOperationException("Downloader already disposed");

Try / catch

try {
    downloader.RequestByteRanges(ranges);
} catch (ObjectDisposedException) {
    downloader = new ByteRangeDownloader(uri, handle, tempFile);
    downloader.RequestByteRanges(ranges);
}

Prevention

When it happens

Trigger: Calling GetDownloadedByteRanges or RequestByteRanges, or reading/writing Proxy, Credentials, CachePolicy, or FileMutex after downloader.Dispose().

Common situations: Race conditions where one thread disposes the downloader while another still uses it, or continued use in a finally block / cache after disposal.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/1dcc8a47a3737551. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/IO/Packaging/ByteRangeDownloader.cs:390

        //------------------------------------------------------

        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------

        #region Private Methods

        /// <summary>
        /// Check if the object is disposed
        /// </summary>
        /// <remarks>this._disposed is not changed by a thread while another thread is calling this function</remarks>
        private void CheckDisposed()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(null, SR.ByteRangeDownloaderDisposed);
            }
        }

        /// <summary>
        /// Constructor for ByteRangeDownloader
        /// </summary>
        private ByteRangeDownloader(Uri requestedUri, SafeWaitHandle eventHandle)
        {
            ArgumentNullException.ThrowIfNull(requestedUri);

            // Ensure uri is correct scheme (http or https) Do case-sensitive comparison since Uri.Scheme contract is to return in lower case only.
            if (!string.Equals(requestedUri.Scheme, Uri.UriSchemeHttp, StringComparison.Ordinal) && !string.Equals(requestedUri.Scheme, Uri.UriSchemeHttps, StringComparison.Ordinal))
            {
                throw new ArgumentException(SR.InvalidScheme, nameof(requestedUri));
            }

            ArgumentNullException.ThrowIfNull(eventHandle);

View on GitHub (pinned to 81131a70a4)