jstedfast/MailKit · error · ArgumentException

One or more annotations does not define any attributes.

Error message

One or more annotations does not define any attributes.

What it means

ImapUtils.FormatAnnotations validates the annotation list before building an IMAP ANNOTATE command. If any ImapAnnotation in the collection has no Properties, the command would be malformed, so MailKit throws an ArgumentException naming the 'annotations' parameter (or silently skips the annotation when throwOnError is false).

Solutions

  1. Before storing, filter or check annotations: ensure every ImapAnnotation has at least one property via annotation.Properties.Count > 0.
  2. Populate each ImapAnnotation with SetProperty(...)/properties for the entries you intend to write.
  3. Remove empty ImapAnnotation instances from the StoreRequest/annotation collection before calling StoreAsync.

Example fix

// before
var annotation = new ImapAnnotation("/comment");
request.Annotations.Add(annotation);
await client.Inbox.StoreAsync(request);

// after
var annotation = new ImapAnnotation("/comment");
annotation.SetProperty("value.priv", "my comment");
if (annotation.Properties.Count > 0)
{
    request.Annotations.Add(annotation);
    await client.Inbox.StoreAsync(request);
}
Defensive patterns

Strategy: validation

Validate before calling

if (annotations == null || annotations.Count == 0 || annotations.Any(a => a.Properties.Count == 0))
    throw new ArgumentException("all annotations must define at least one property", nameof(annotations));

Prevention

When it happens

Trigger: Calling ImapClient.StoreAsync with a store request containing annotations where the ImapAnnotation's Properties dictionary/annotation was constructed empty, e.g. new ImapAnnotation(entry) with no calls to SetProperty.

Common situations: Dynamically building annotations from user/config data where an empty result slips through; copying annotations from a fetched message that had none; typos that skip property population.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15). Data as JSON: /api/errors/31af0974c7d48ab9. Report an issue: GitHub.

Appendix: source

Thrown at MailKit/Net/Imap/ImapUtils.cs:215

		/// Formats a list of annotations for a STORE or APPEND command.
		/// </summary>
		/// <param name="command">The command builder.</param>
		/// <param name="annotations">The annotations.</param>
		/// <param name="args">the argument list.</param>
		/// <param name="throwOnError">Throw an exception if there are any annotations without properties.</param>
		public static void FormatAnnotations (StringBuilder command, IList<Annotation> annotations, List<object> args, bool throwOnError)
		{
			int length = command.Length;
			int added = 0;

			command.Append ("ANNOTATION (");

			for (int i = 0; i < annotations.Count; i++) {
				var annotation = annotations[i];

				if (annotation.Properties.Count == 0) {
					if (throwOnError)
						throw new ArgumentException ("One or more annotations does not define any attributes.", nameof (annotations));

					continue;
				}

				command.Append (annotation.Entry);
				command.Append (" (");

				foreach (var property in annotation.Properties) {
					command.Append (property.Key);

					if (property.Value != null) {
						command.Append (" %S ");
						args.Add (property.Value);
					} else {
						command.Append (" NIL ");
					}
				}

View on GitHub (pinned to 9d3859a785)