{"record":{"id":"8933093999adf93d","repo":"jstedfast/MailKit","slug":"the-imapclient-is-currently-busy-processing-a-command-in","errorCode":null,"errorMessage":"The ImapClient is currently busy processing a command in another thread. Lock the SyncRoot property to properly synchronize your threads.","messagePattern":"The ImapClient is currently busy processing a command in another thread\\. Lock the SyncRoot property to properly synchronize your threads\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"MailKit/Net/Imap/ImapEngine.cs","lineNumber":3136,"sourceCode":"\t\t\t\t} else if (atom.Equals (\"VANISHED\", StringComparison.OrdinalIgnoreCase) && folder != null) {\n\t\t\t\t\tawait folder.OnVanishedAsync (this, cancellationToken).ConfigureAwait (false);\n\t\t\t\t\tawait SkipLineAsync (cancellationToken).ConfigureAwait (false);\n\t\t\t\t} else {\n\t\t\t\t\t// don't know how to handle this... eat it?\n\t\t\t\t\tawait SkipLineAsync (cancellationToken).ConfigureAwait (false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t[MemberNotNull (nameof (current))]\n\t\tvoid PopNextCommand ()\n\t\t{\n\t\t\tlock (queue) {\n\t\t\t\tif (queue.Count == 0)\n\t\t\t\t\tthrow new InvalidOperationException (\"The IMAP command queue is empty.\");\n\n\t\t\t\tif (IsBusy)\n\t\t\t\t\tthrow new InvalidOperationException (\"The ImapClient is currently busy processing a command in another thread. Lock the SyncRoot property to properly synchronize your threads.\");\n\n\t\t\t\tcurrent = queue[0];\n\t\t\t\tqueue.RemoveAt (0);\n\n\t\t\t\ttry {\n\t\t\t\t\tcurrent.CancellationToken.ThrowIfCancellationRequested ();\n\t\t\t\t} catch {\n\t\t\t\t\tqueue.RemoveAll (x => x.CancellationToken.IsCancellationRequested);\n\t\t\t\t\tcurrent = null;\n\t\t\t\t\tthrow;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Handles an IMAP protocol exception by disconnecting and then potentially throwing a replacement exception.\n\t\t/// </summary>\n\t\t/// <param name=\"ic\">The current <see cref=\"ImapCommand\"/> being processed.</param>","sourceCodeStart":3118,"sourceCodeEnd":3154,"githubUrl":"https://github.com/jstedfast/MailKit/blob/9d3859a7855e3e17582c07fd01972b8e262bf176/MailKit/Net/Imap/ImapEngine.cs#L3118-L3154","documentation":"PopNextCommand() throws this when the engine tries to dequeue the next command while ImapClient is already busy processing a command on another thread. MailKit requires that multi-threaded users synchronize access with the ImapClient.SyncRoot lock; this error is the library telling you that contract was violated.","triggerScenarios":"Two threads calling any ImapClient/ImapMailbox API (e.g. one calling Fetch, another calling Search or Noop) on the same connected client without holding SyncRoot; queueing a command while the engine loop is mid-command.","commonSituations":"A UI timer doing NOOP keepalive while a background task fetches messages; parallel Task.WhenAll over multiple mailbox operations on one client; code that queues commands but forgets the lock that existed in older versions.","solutions":["Lock imapClient.SyncRoot around every command-issuing call (Sync APIs): lock (imapClient.SyncRoot) { client.Inbox.Fetch(...) }","Use the async APIs instead of calling Sync APIs from worker threads, so a single engine task processes commands sequentially","Give each concurrent worker its own ImapClient/IImapClient connection","Refactor to a single consumer thread that serializes all IMAP operations"],"exampleFix":"// before\nvar task1 = Task.Run(() => client.Inbox.Fetch(0, 10, summary));\nvar task2 = Task.Run(() => client.Inbox.Search(query));\n\n// after\nlock (client.SyncRoot) {\n    var msgs = client.Inbox.Fetch(0, 10, summary);\n    var uids = client.Inbox.Search(query);\n}","handlingStrategy":"validation","validationCode":"bool SafeToRun(ImapClient client) {\n    lock (client.SyncRoot) { return !client.IsBusy && client.IsConnected; }\n}","typeGuard":"null","tryCatchPattern":"try {\n    // synchronized IMAP work\n} catch (InvalidOperationException ex) when (ex.Message.Contains(\"currently busy\")) {\n    logger.Warn(\"ImapClient contention detected - serializing access\");\n    lock (client.SyncRoot) { /* retry once under lock */ }\n}","preventionTips":["Centralize all IMAP access behind one synchronized service class","Never share one ImapClient across parallel Tasks","Convert legacy Sync calls to Async equivalents","Document SyncRoot locking as a project convention"],"tags":["concurrency","imap","threading","race-condition"],"backgroundTag":"thread-interrupted","analyzedSha":"9d3859a7855e3e17582c07fd01972b8e262bf176","analyzedAt":"2026-09-15T15:46:11.592Z","contentChangedAt":"2026-09-15T15:46:11.592Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}