jstedfast/MailKit · error · ArgumentException

The doneToken must be cancellable.

Error message

The doneToken must be cancellable.

What it means

ImapClient.IdleAsync (via CheckCanIdle) requires the doneToken CancellationToken to be cancellable so the IDLE session can be terminated. A CancellationToken.None or default token can never be canceled, which would leave the client stuck in IDLE forever.

Solutions

  1. Create a real token: var cts = new CancellationTokenSource(); and pass cts.Token
  2. Cancel the token (cts.Cancel()) to end the IDLE session when done
  3. Pass an existing application-level shutdown token instead of CancellationToken.None

Example fix

// before
await client.IdleAsync(folder, CancellationToken.None);
// after
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(9));
await client.IdleAsync(folder, cts.Token);
Defensive patterns

Strategy: validation

Validate before calling

if (!doneToken.CanBeCanceled)
    throw new ArgumentException("doneToken must be cancellable");

Try / catch

try { await folder.IdleAsync(doneToken); }
catch (ArgumentException) { /* pass a real CTS token and retry */ }

Prevention

When it happens

Trigger: Calling IdleAsync(folder, CancellationToken.None) or passing `default`; constructing a token via `new CancellationToken()` without any source.

Common situations: Code generated by passing CancellationToken.None everywhere as a placeholder; unit tests that use a default token; misunderstanding that doneToken is optional like a normal cancellationToken.

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

Appendix: source

Thrown at MailKit/Net/Imap/ImapClient.cs:1915

		/// <exception cref="ImapCommandException">
		/// The server replied to the NOOP command with a NO or BAD response.
		/// </exception>
		/// <exception cref="ImapProtocolException">
		/// The server responded with an unexpected token.
		/// </exception>
		public override void NoOp (CancellationToken cancellationToken = default)
		{
			var ic = QueueNoOpCommand (cancellationToken);

			engine.Run (ic);

			ProcessNoOpResponse (ic);
		}

		void CheckCanIdle (CancellationToken doneToken)
		{
			if (!doneToken.CanBeCanceled)
				throw new ArgumentException ("The doneToken must be cancellable.", nameof (doneToken));

			CheckDisposed ();
			CheckConnected ();
			CheckAuthenticated ();

			if ((engine.Capabilities & ImapCapabilities.Idle) == 0)
				throw new NotSupportedException ("The IMAP server does not support the IDLE extension.");

			if (engine.State != ImapEngineState.Selected)
				throw new InvalidOperationException ("An ImapFolder has not been opened.");
		}

		ImapCommand QueueIdleCommand (ImapIdleContext context, CancellationToken cancellationToken)
		{
			var ic = engine.QueueCommand (cancellationToken, null, "IDLE\r\n");
			ic.ContinuationHandler = context.ContinuationHandler;
			ic.UserData = context;

View on GitHub (pinned to 9d3859a785)