dotnet/wpf · error · ObjectDisposedException

EncryptedPackageEnvelope object was disposed.

Error message

EncryptedPackageEnvelope object was disposed.

What it means

CheckDisposed guards every public accessor of EncryptedPackageEnvelope (Flush, RightsManagementInformation, PackageProperties, FileOpenAccess, GetPackage, StorageInfo). After Dispose, any of these members throws ObjectDisposedException because the underlying compound file has been released.

Solutions

  1. Keep all envelope usage inside the scope where it is not disposed; move using blocks outward to cover all accesses
  2. Reopen the envelope (EncryptedPackageEnvelope.Open) if you need access after disposal
  3. Check _disposed-equivalent via a wrapper: track disposal in your own code and avoid calling members afterwards

Example fix

// before
EncryptedPackageEnvelope env;
using (env = EncryptedPackageEnvelope.Open(path)) { }
var props = env.PackageProperties; // ObjectDisposedException
// after
using (var env = EncryptedPackageEnvelope.Open(path))
{
    var props = env.PackageProperties; // access inside scope
}
Defensive patterns

Strategy: type-guard

Validate before calling

// track disposal in a wrapper
bool _disposed;
void UseEnvelope(EncryptedPackageEnvelope env) { if (_disposed) throw new ObjectDisposedException(nameof(env)); }

Type guard

bool IsUsable(EncryptedPackageEnvelope env, Func<object> probe) { try { probe(); return true; } catch (ObjectDisposedException) { return false; } }

Try / catch

try { var props = env.PackageProperties; }
catch (ObjectDisposedException) { env = EncryptedPackageEnvelope.Open(path); /* reopen */ }

Prevention

When it happens

Trigger: Using an EncryptedPackageEnvelope after calling Dispose (explicitly or via using-block exit), e.g. reading PackageProperties after the using scope ends, or caching the envelope and using it after disposal.

Common situations: Returning the envelope from a method whose using block closed it; storing the envelope in a field while disposing it in another code path; double-dispose followed by further use.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/EncryptedPackage.cs:1064

            {
                //
                // By setting _disposed = true, we ensure that all future accesses to
                // this object will fail (because all public methods and property accessors
                // call CheckDisposed). Note that we do -not- wrap the entire body of
                // Dispose(bool) (this method) in an "if (!_disposed)". This is safe
                // because we set each reference to null immediately after attempting
                // to release it, so we never attempt to release any reference more
                // than once.
                //
                _disposed = true;         
            }
        }

        private void
        CheckDisposed()
        {
            if (_disposed)
                throw new ObjectDisposedException(null, SR.EncryptedPackageEnvelopeDisposed);
        }

        /// <summary>
        /// Create a stream in the "encrypted" data space to hold the package
        /// contents, and copy the package into that stream.
        /// </summary>
        /// <param name="packageStream">
        /// A stream containing an unencrypted package which is to be stored in
        /// the compound file.
        /// </param>
        private void
        EmbedPackage(Stream packageStream)
        {
            StreamInfo siPackage = new StreamInfo(_root, PackageStreamName);

            Debug.Assert(!siPackage.InternalExists());

            //

View on GitHub (pinned to 81131a70a4)