{"record":{"id":"f56ac788711874ed","repo":"jstedfast/MailKit","slug":"syntax-error-in-untagged-expunge-response-unexpected-message","errorCode":null,"errorMessage":"Syntax error in untagged EXPUNGE response. Unexpected message index: 0","messagePattern":"Syntax error in untagged EXPUNGE response\\. Unexpected message index: 0","errorType":"exception","errorClass":"ImapProtocolException","httpStatus":null,"severity":"error","filePath":"MailKit/Net/Imap/ImapEngine.cs","lineNumber":2927,"sourceCode":"\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (uint.TryParse (atom, NumberStyles.None, CultureInfo.InvariantCulture, out uint number)) {\n\t\t\t\t\t// we probably have something like \"* 1 EXISTS\"\n\t\t\t\t\ttoken = ReadToken (cancellationToken);\n\n\t\t\t\t\tAssertToken (token, ImapTokenType.Atom, \"Syntax error in untagged response. {0}\", token);\n\n\t\t\t\t\tatom = (string) token.Value;\n\n\t\t\t\t\tif (ic.UntaggedHandlers.TryGetValue (atom, out handler)) {\n\t\t\t\t\t\t// the command registered an untagged handler for this atom...\n\t\t\t\t\t\thandler (this, ic, (int) number - 1, false).GetAwaiter ().GetResult ();\n\t\t\t\t\t} else if (folder != null) {\n\t\t\t\t\t\tif (atom.Equals (\"EXISTS\", StringComparison.OrdinalIgnoreCase)) {\n\t\t\t\t\t\t\tfolder.OnExists ((int) number);\n\t\t\t\t\t\t} else if (atom.Equals (\"EXPUNGE\", StringComparison.OrdinalIgnoreCase)) {\n\t\t\t\t\t\t\tif (number == 0)\n\t\t\t\t\t\t\t\tthrow UnexpectedToken (\"Syntax error in untagged EXPUNGE response. Unexpected message index: 0\");\n\n\t\t\t\t\t\t\tfolder.OnExpunge ((int) number - 1);\n\t\t\t\t\t\t} else if (atom.Equals (\"FETCH\", StringComparison.OrdinalIgnoreCase)) {\n\t\t\t\t\t\t\t// Apparently Courier-IMAP (2004) will reply with \"* 0 FETCH ...\" sometimes.\n\t\t\t\t\t\t\t// See https://github.com/jstedfast/MailKit/issues/428 for details.\n\t\t\t\t\t\t\t//if (number == 0)\n\t\t\t\t\t\t\t//\tthrow UnexpectedToken (\"Syntax error in untagged FETCH response. Unexpected message index: 0\");\n\n\t\t\t\t\t\t\tfolder.OnUntaggedFetchResponse (this, (int) number - 1, cancellationToken);\n\t\t\t\t\t\t} else if (atom.Equals (\"RECENT\", StringComparison.OrdinalIgnoreCase)) {\n\t\t\t\t\t\t\tfolder.OnRecent ((int) number);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t//Debug.WriteLine (\"Unhandled untagged response: * {0} {1}\", number, atom);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t//Debug.WriteLine (\"Unhandled untagged response: * {0} {1}\", number, atom);\n\t\t\t\t\t}\n","sourceCodeStart":2909,"sourceCodeEnd":2945,"githubUrl":"https://github.com/jstedfast/MailKit/blob/9d3859a7855e3e17582c07fd01972b8e262bf176/MailKit/Net/Imap/ImapEngine.cs#L2909-L2945","documentation":"Thrown when an untagged EXPUNGE response reports message index 0, which is impossible: IMAP sequence numbers are 1-based. MailKit throws because subtracting 1 would yield an invalid index (-1) for OnExpunge. This is raised in the synchronous untagged-response processing path.","triggerScenarios":"The server sends `* 0 EXPUNGE` while MailKit processes untagged responses during a synchronous command (e.g. after a command issued on ImapFolder, or during NoOp/Check when updates are drained).","commonSituations":"Known bug class in older/broken IMAP servers (similar to the Courier-IMAP `* 0 FETCH` quirk documented in MailKit issue #428); custom or in-house server implementations emitting 0-based indices; buggy proxies translating responses.","solutions":["Inspect the protocol log to confirm the server emitted `* 0 EXPUNGE`","Update or fix the IMAP server — a 1-based sequence number of 0 is a server bug per RFC 3501","Upgrade MailKit; check release notes for relaxed handling of zero-valued untagged responses","If a proxy rewrites sequence numbers, correct its 1-based indexing","Work around by wrapping folder operations in try/catch for ImapProtocolException and issuing NOOP/re-sync if your server is known-buggy"],"exampleFix":"// before\n// server: * 0 EXPUNGE\n// after\n// server: * 1 EXPUNGE   (1-based sequence number per RFC 3501)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    folder.NoOp (); // drains untagged responses, may hit EXPUNGE parse\n} catch (ImapProtocolException ex) {\n    logger.LogError (ex, \"Server sent '* 0 EXPUNGE' - server bug\");\n    // resync: reopen the folder to rebuild the message index\n    folder.Close (false);\n    folder.Open (FolderAccess.ReadWrite);\n}","preventionTips":["Audit your IMAP server/proxy for 0-based sequence-number bugs (compare to Courier `* 0 FETCH` quirk, MailKit issue #428)","Run protocol logging in staging with realistic expunge workloads","Keep MailKit updated for quirk-mode handling","On known-buggy servers, plan periodic folder re-open/resync"],"tags":["imap","expunge","sequence-number","protocol-parse"],"backgroundTag":"unexpected-response-shape","analyzedSha":"9d3859a7855e3e17582c07fd01972b8e262bf176","analyzedAt":"2026-09-15T15:46:11.592Z","contentChangedAt":"2026-09-15T15:46:11.592Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}