jstedfast/MailKit · error · NotSupportedException

The IMAP server does not support negative partial ranges.

Error message

The IMAP server does not support negative partial ranges.

What it means

MailKit throws this NotSupportedException when a PartialRange with a negative First value is passed to Search but the server only supports the RFC 5267 CONTEXT=SEARCH form of partial returns, not RFC 9394's PARTIAL capability. Negative offsets (counting from the end of the result set) were introduced in RFC 9394 and are meaningless to servers implementing only the older spec.

Solutions

  1. Verify client.Capabilities.HasFlag(ImapCapabilities.Partial) before using negative PartialRange offsets.
  2. On servers without PARTIAL, sort the query (e.g. by date descending via SORT) and take a positive range from the front of the results.
  3. Retrieve the full result set and apply the negative-offset logic in application code.
  4. Use a server supporting RFC 9394 if negative ranges are essential.

Example fix

// before
var results = folder.Search (SearchOptions.None, query, new PartialRange (-10, 10)); // last 10

// after
var partial = client.Capabilities.HasFlag (ImapCapabilities.Partial)
    ? new PartialRange (-10, 10)
    : new PartialRange (0, 10); // combined with reverse-ordered sort query
Defensive patterns

Strategy: validation

Validate before calling

if (partialRange.HasValue && partialRange.Value.First < 0 &&
    !client.Capabilities.HasFlag (ImapCapabilities.Partial))
    throw new InvalidOperationException ("Negative partial ranges require the RFC 9394 PARTIAL capability");

Try / catch

try {
    results = folder.Search (SearchOptions.None, query, partialRange);
} catch (NotSupportedException) {
    results = ReverseSortAndTake (folder, query, count: -partialRange.Value.First);
}

Prevention

When it happens

Trigger: Calling folder.Search(options, query, new PartialRange(-10, 5)) (or async) on a server that has ImapCapabilities.Context with "SEARCH" but not ImapCapabilities.Partial. A positive range would have passed via the Context check.

Common situations: Trying to get 'the last N results' using a negative offset against servers that support RFC 5267 but not RFC 9394 (most servers today).

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at MailKit/Net/Imap/ImapFolderSearch.cs:1056

		{
			if (query == null)
				throw new ArgumentNullException (nameof (query));

			CheckState (true, false);

			if (options != SearchOptions.None && (Engine.Capabilities & ImapCapabilities.ESearch) == 0)
				throw new NotSupportedException ("The IMAP server does not support the ESEARCH extension.");

			if (partialRange.HasValue) {
				// Note: RFC 9394 advertises the "PARTIAL" capability while RFC 5267 defines the same PARTIAL
				// search return option under the "CONTEXT=SEARCH" capability.
				if ((Engine.Capabilities & ImapCapabilities.Partial) == 0 &&
					((Engine.Capabilities & ImapCapabilities.Context) == 0 || !Engine.SupportedContexts.Contains ("SEARCH")))
					throw new NotSupportedException ("The IMAP server does not support the PARTIAL extension.");

				// Note: Negative partial ranges were introduced in RFC 9394 and are not defined by RFC 5267.
				if (partialRange.Value.First < 0 && (Engine.Capabilities & ImapCapabilities.Partial) == 0)
					throw new NotSupportedException ("The IMAP server does not support negative partial ranges.");
			}

			var args = new List<object> ();
			var optimized = query.Optimize (new ImapSearchQueryOptimizer ());
			var expr = BuildQueryExpression (optimized, args, out charset);
			var command = new StringBuilder ("UID SEARCH ");

			if ((Engine.Capabilities & ImapCapabilities.ESearch) != 0 || partialRange.HasValue) {
				command.Append ("RETURN (");

				if (options != SearchOptions.All && options != SearchOptions.None) {
					if ((options & SearchOptions.All) != 0)
						command.Append ("ALL ");
					if ((options & SearchOptions.Relevancy) != 0)
						command.Append ("RELEVANCY ");
					if ((options & SearchOptions.Count) != 0)
						command.Append ("COUNT ");
					if ((options & SearchOptions.Min) != 0)

View on GitHub (pinned to 9d3859a785)