{"record":{"id":"22b6ef3ac45df1c2","repo":"jstedfast/MailKit","slug":"invalid-annotation-entry","errorCode":null,"errorMessage":"Invalid annotation entry.","messagePattern":"Invalid annotation entry\\.","errorType":"validation","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"MailKit/AnnotationEntry.cs","lineNumber":447,"sourceCode":"\t\t\tif (entry.Length == 0)\n\t\t\t\tthrow new FormatException (\"An annotation entry cannot be empty.\");\n\n\t\t\tif (entry[0] != '/' && entry[0] != '*' && entry[0] != '%')\n\t\t\t\tthrow new FormatException (\"An annotation entry must begin with a '/' character.\");\n\n\t\t\tvar scope = AnnotationScope.Both;\n\t\t\tint startIndex = 0, endIndex;\n\t\t\tstring? partSpecifier = null;\n\t\t\tvar component = 0;\n\t\t\tvar pc = entry[0];\n\t\t\tstring path;\n\n\t\t\tfor (int i = 1; i < entry.Length; i++) {\n\t\t\t\tchar c = entry[i];\n\n\t\t\t\tif (c >= '0' && c <= '9' && pc == '/') {\n\t\t\t\t\tif (component > 0)\n\t\t\t\t\t\tthrow new FormatException (\"Invalid annotation entry.\");\n\n\t\t\t\t\tstartIndex = i;\n\t\t\t\t\tendIndex = i + 1;\n\t\t\t\t\tpc = c;\n\n\t\t\t\t\twhile (endIndex < entry.Length) {\n\t\t\t\t\t\tc = entry[endIndex];\n\n\t\t\t\t\t\tif (c == '/') {\n\t\t\t\t\t\t\tif (pc == '.')\n\t\t\t\t\t\t\t\tthrow new FormatException (\"Invalid part-specifier in annotation entry.\");\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!(c >= '0' && c <= '9') && c != '.')\n\t\t\t\t\t\t\tthrow new FormatException ($\"Invalid character in part-specifier: '{c}'.\");\n","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/jstedfast/MailKit/blob/9d3859a7855e3e17582c07fd01972b8e262bf176/MailKit/AnnotationEntry.cs#L429-L465","documentation":"During parsing, AnnotationEntry.Parse throws FormatException with \"Invalid annotation entry.\" when the structure after the leading character is malformed — here, when a digit follows '/' but a numeric component was already parsed (component > 0), meaning two part-number components were not separated correctly.","triggerScenarios":"Parsing entries with misplaced digits after '/', e.g. \"/1/2comment.priv\", duplicate numeric components, or otherwise structurally broken entry strings that pass the first-character check but fail the component scanner.","commonSituations":"Hand-writing entry strings instead of using the server's exact format; corrupted or truncated entry strings from logs/config; entries from non-conformant servers.","solutions":["Use the exact entry string returned by the IMAP server (e.g. from Fetch/GetAnnotations output) rather than hand-constructed ones","Validate the entry against RFC 5257 syntax: '/' ['.part'] path ('.priv'|'.shared'|'.priv.shared')","Catch FormatException around Parse and log/skip the offending entry","Round-trip: construct entries with AnnotationEntry.Create instead of parsing ad-hoc strings"],"exampleFix":"// before\nvar annotation = AnnotationEntry.Parse (\"/1/2comment.priv\");\n// after\nvar annotation = AnnotationEntry.Parse (\"/1.comment.priv\");","handlingStrategy":"try-catch","validationCode":"static bool LooksLikeEntry (string entry) =>\n    System.Text.RegularExpressions.Regex.IsMatch (\n        entry, @\"^[/*%](\\.?\\d+)?[^.]+(\\.priv|\\.shared|\\.priv\\.shared)$\");","typeGuard":null,"tryCatchPattern":"try {\n    var annotation = AnnotationEntry.Parse (entry);\n} catch (FormatException ex) {\n    logger.LogError (ex, \"Malformed annotation entry: {Entry}\", entry);\n    // skip or fall back to constructing via AnnotationEntry.Create\n}","preventionTips":["Prefer AnnotationEntry.Create over parsing hand-built strings","Feed Parse only entry strings returned by the IMAP server","Add a round-trip test: Create -> ToString -> Parse for your entry formats"],"tags":["imap","annotation","parsing","format"],"backgroundTag":"invalid-argument-format","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"}