jstedfast/MailKit · error · ObjectDisposedException

ObjectDisposedException

Error message

ObjectDisposedException

What it means

CheckDisposed throws ObjectDisposedException(nameof(DuplexStream)) when Read, ReadAsync, Write, WriteAsync, Flush or FlushAsync is called after Dispose has run. It protects against using an underlying duplex pipe whose resources were already released.

Solutions

  1. Ensure all I/O on the stream completes (await tasks) before Dispose; check for unawaited async operations.
  2. Keep the stream alive for the duration of its use; widen the using scope or switch to explicit Dispose at the correct point.
  3. If lifecycle is racy, check for disposal via your own flag or catch ObjectDisposedException around late operations.

Example fix

// before
using (var duplex = new DuplexStream (a, b)) {
    var task = duplex.ReadAsync (buffer, 0, buffer.Length);
}
var n = await task; // throws
// after
using (var duplex = new DuplexStream (a, b)) {
    var n = await duplex.ReadAsync (buffer, 0, buffer.Length);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!ownStream) { /* track lifetime with your own disposed flag before use */ }
private bool disposed;
if (disposed) return; // caller-side guard

Try / catch

try { await stream.ReadAsync (buffer, 0, buffer.Length); }
catch (ObjectDisposedException) { /* stream already disposed: re-acquire or abort */ }

Prevention

When it happens

Trigger: Calling any read/write/flush method on a DuplexStream after Dispose() (or a 'using' block scope that has exited), including async continuations that run after the using block ends.

Common situations: Firing async read/write tasks and disposing the stream before they complete (e.g. cancellation without awaiting); storing the stream in a field and reusing it after a using scope; double-dispose followed by retry logic.

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 jstedfast/MailKit@9d3859a785 (2026-09-15). Data as JSON: /api/errors/9809cf8783fcc68e. Report an issue: GitHub.

Appendix: source

Thrown at MailKit/DuplexStream.cs:170

			get { throw new NotSupportedException (); }
		}

		static void ValidateArguments (byte[] buffer, int offset, int count)
		{
			if (buffer == null)
				throw new ArgumentNullException (nameof (buffer));

			if (offset < 0 || offset > buffer.Length)
				throw new ArgumentOutOfRangeException (nameof (offset));

			if (count < 0 || count > (buffer.Length - offset))
				throw new ArgumentOutOfRangeException (nameof (count));
		}

		void CheckDisposed ()
		{
			if (disposed)
				throw new ObjectDisposedException (nameof (DuplexStream));
		}

		/// <summary>
		/// Reads a sequence of bytes from the stream and advances the position
		/// within the stream by the number of bytes read.
		/// </summary>
		/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many
		/// bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
		/// <param name="buffer">The buffer.</param>
		/// <param name="offset">The buffer offset.</param>
		/// <param name="count">The number of bytes to read.</param>
		/// <exception cref="System.ArgumentNullException">
		/// <paramref name="buffer"/> is <see langword="null" />.
		/// </exception>
		/// <exception cref="System.ArgumentOutOfRangeException">
		/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
		/// <para>-or-</para>
		/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes starting

View on GitHub (pinned to 9d3859a785)