jstedfast/MailKit · error · ArgumentException
Annotation attribute specifiers cannot contain '*' or '%'.
Error message
Annotation attribute specifiers cannot contain '*' or '%'.
What it means
The AnnotationAttribute constructor throws ArgumentException when the specifier contains IMAP mailbox wildcards '*' or '%'. Attribute specifiers name attributes of an entry, not mailboxes, so wildcard characters are rejected (validation is intentionally minimal — see the TODO in the source).
Solutions
- Remove any '*' or '%' characters from the specifier before constructing AnnotationAttribute.
- Use the correct literal attribute names (e.g. "/private/comment", "value.privacy").
- If wildcard matching is intended, that belongs in entry-selector/matching logic, not the attribute specifier.
Example fix
// before
var attr = new AnnotationAttribute("/private/*");
// after
var attr = new AnnotationAttribute("/private/comment"); Defensive patterns
Strategy: validation
Validate before calling
if (specifier.IndexOfAny(new[] {'*','%'}) != -1)
throw new FormatException("Attribute specifier must not contain IMAP wildcards");
var attr = new AnnotationAttribute(specifier); Type guard
bool IsValidSpecifier(string s) => !string.IsNullOrEmpty(s) && s.IndexOfAny(new[] {'*','%'}) == -1; Try / catch
try
{
var attr = new AnnotationAttribute(specifier);
}
catch (ArgumentException)
{
// strip wildcards or use the literal attribute name
specifier = specifier.Replace("*", "").Replace("%", "");
} Prevention
- Do not reuse mailbox wildcard patterns as attribute specifiers.
- Keep a whitelist of valid attribute names ("/private", "/shared", "value", etc.).
- Sanitize user input before it reaches the constructor.
When it happens
Trigger: Calling `new AnnotationAttribute("/priv*")` or passing a mailbox-style pattern (e.g. "%", "INBOX*", strings copied from mailbox wildcard matching code) as an attribute specifier.
Common situations: Confusing IMAP mailbox wildcards (used in folder listing) with annotation entry/attribute specifiers; building a specifier by concatenating a user-supplied pattern.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Value cannot be null. (Parameter 'specifier')
- Annotation attribute specifiers cannot be empty.
- Value cannot be null. (Parameter 'path')
- Annotation entry paths cannot be empty.
- Annotation entry paths must begin with '/'.
AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15).
Data as JSON: /api/errors/531b8874a189e5c1.
Report an issue: GitHub.
Appendix: source
Thrown at MailKit/AnnotationAttribute.cs:124
/// </remarks>
/// <param name="specifier">The annotation attribute specifier.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="specifier"/> is <see langword="null" />.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="specifier"/> contains illegal characters.
/// </exception>
public AnnotationAttribute (string specifier)
{
if (specifier == null)
throw new ArgumentNullException (nameof (specifier));
if (specifier.Length == 0)
throw new ArgumentException ("Annotation attribute specifiers cannot be empty.", nameof (specifier));
// TODO: improve validation
if (specifier.IndexOfAny (Wildcards) != -1)
throw new ArgumentException ("Annotation attribute specifiers cannot contain '*' or '%'.", nameof (specifier));
Specifier = specifier;
if (specifier.EndsWith (".shared", StringComparison.Ordinal)) {
Name = specifier.Substring (0, specifier.Length - ".shared".Length);
Scope = AnnotationScope.Shared;
} else if (specifier.EndsWith (".priv", StringComparison.Ordinal)) {
Name = specifier.Substring (0, specifier.Length - ".priv".Length);
Scope = AnnotationScope.Private;
} else {
Scope = AnnotationScope.Both;
Name = specifier;
}
}
/// <summary>
/// Get the name of the annotation attribute.
/// </summary>View on GitHub (pinned to 9d3859a785)