jstedfast/MailKit · error · InvalidOperationException

An ImapFolder has not been opened.

Error message

An ImapFolder has not been opened.

What it means

CheckCanIdle throws this InvalidOperationException when the engine state is not Selected, i.e. no folder (ImapFolder) has been opened on the connection before starting IDLE. IDLE only makes sense within the selected-state of a mailbox.

Solutions

  1. Open a folder first: var folder = client.GetFolder(...); folder.Open(FolderAccess.ReadWrite);
  2. Re-select the folder after any reconnect before resuming IDLE
  3. Check folder.IsOpen before starting the idle loop

Example fix

// before
await client.IdleAsync(null, doneToken);
// after
var inbox = client.Inbox;
await inbox.OpenAsync(FolderAccess.ReadWrite);
await inbox.IdleAsync(doneToken);
Defensive patterns

Strategy: validation

Validate before calling

if (folder == null || !folder.IsOpen)
    await folder.OpenAsync(FolderAccess.ReadWrite);

Type guard

bool ReadyForIdle(IMailFolder f) => f is { IsOpen: true };

Try / catch

try { await folder.IdleAsync(doneToken); }
catch (InvalidOperationException) { await folder.OpenAsync(FolderAccess.ReadWrite); await folder.IdleAsync(doneToken); }

Prevention

When it happens

Trigger: Calling IdleAsync before any folder.Open(...) succeeded; the selected folder was closed or the connection reset to authenticated state; calling idle on a raw ImapClient connection after folder open failed.

Common situations: Startup ordering bug where idle listener starts before folder selection completes; folder.Open threw earlier and the code continued to idle; reconnect logic re-established connection but did not re-select the folder.

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/9a8c680cb463e4e0. Report an issue: GitHub.

Appendix: source

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

			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;

			return ic;
		}

		static void ProcessIdleResponse (ImapCommand ic)
		{
			ic.ThrowIfNotOk ("IDLE");
		}

		/// <summary>
		/// Toggle the <see cref="ImapClient"/> into the IDLE state.

View on GitHub (pinned to 9d3859a785)