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
- Open a folder first: var folder = client.GetFolder(...); folder.Open(FolderAccess.ReadWrite);
- Re-select the folder after any reconnect before resuming IDLE
- 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
- Always Open a folder before starting IDLE
- Re-open the folder after every reconnect
- Sequence startup: connect -> authenticate -> open folder -> idle
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
- The doneToken must be cancellable.
- The IMAP server does not support the IDLE extension.
- Value cannot be null. (Parameter 'name')
- Value cannot be null. (Parameter 'rights')
- Value cannot be null. (Parameter 'array')
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)