jstedfast/MailKit · error · ArgumentNullException

partSpecifier

Error message

partSpecifier

What it means

ArgumentNullException whose Message is the parameter name "partSpecifier", thrown by QueueGetHeadersCommand when GetHeaders(int index, ...) is called with a null part specifier. A non-null specifier (e.g., "1", "1.2", "TEXT") is required to build the FETCH BODY[part.HEADER] query.

Solutions

  1. Pass a concrete specifier such as "1" (the top-level MIME part) or the BodyPart.PartSpecifier from a fresh GetBodyParts call.
  2. Add a null check on the specifier (or the BodyPart it came from) before the call.
  3. Use the GetHeaders(int index) overload without a specifier when you want the full message headers.

Example fix

// before
var headers = folder.GetHeaders(index, bodyPart?.PartSpecifier);

// after
if (bodyPart == null)
    bodyPart = (BodyPartMultipart)folder.GetBodyParts(index);
var headers = folder.GetHeaders(index, bodyPart.PartSpecifier);
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrEmpty(partSpecifier))
    throw new InvalidOperationException("A body part specifier (e.g. \"1\" or \"1.2\") is required.");

Type guard

bool HasSpecifier(BodyPart? part) => !string.IsNullOrEmpty(part?.PartSpecifier);

Try / catch

try { var headers = folder.GetHeaders(index, partSpecifier); }
catch (ArgumentNullException ex) when (ex.ParamName == "partSpecifier") { /* default to "1" or re-fetch structure */ }

Prevention

When it happens

Trigger: Passing null as partSpecifier to GetHeaders(int index, string partSpecifier, ...) — commonly when a BodyPart lookup returned null upstream and the specifier was derived as bodyPart?.PartSpecifier.

Common situations: Chaining `folder.GetBodyPart(...)` results that failed silently; refactored code dropping the default "1" specifier; deserialized BodyPart objects with null PartSpecifier.

Related errors


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

Appendix: source

Thrown at MailKit/Net/Imap/ImapFolderFetch.cs:3056

			try {
				await Engine.RunAsync (ic).ConfigureAwait (false);

				var stream = ProcessGetHeadersResponse (ic, ctx, index);

				return await ParseHeadersAsync (stream, cancellationToken).ConfigureAwait (false);
			} finally {
				ctx.Dispose ();
			}
		}

		ImapCommand QueueGetHeadersCommand (int index, string partSpecifier, CancellationToken cancellationToken, ITransferProgress? progress, out FetchStreamContext ctx, out string[] tags)
		{
			if (index < 0 || index >= Count)
				throw new ArgumentOutOfRangeException (nameof (index));

			if (partSpecifier == null)
				throw new ArgumentNullException (nameof (partSpecifier));

			CheckState (true, false);

			var command = string.Format ("FETCH {0} ({1})\r\n", index + 1, GetBodyPartQuery (partSpecifier, true, out tags));
			var ic = new ImapCommand (Engine, cancellationToken, this, command);
			ic.RegisterUntaggedHandler ("FETCH", FetchStreamHandler);
			ic.UserData = ctx = new FetchStreamContext (progress);

			Engine.QueueCommand (ic);

			return ic;
		}

		Stream ProcessGetHeadersResponse (ImapCommand ic, FetchStreamContext ctx, int index, string[] tags)
		{
			ProcessFetchResponse (ic);

			if (!ctx.TryGetSection (index, tags[0], out var section, true))

View on GitHub (pinned to 9d3859a785)