jstedfast/MailKit · error · SaslException

IncompleteChallenge

IncompleteChallenge

Error message

Server response contained incomplete authentication data.

What it means

In the DIGEST-MD5 final step, the server's response must be a key/value pair whose key is 'rspauth'; otherwise the response is incomplete. SaslMechanismDigestMd5.Challenge throws SaslException with code SaslErrorCode.IncompleteChallenge when TryParseKeyValuePair fails to parse the server data.

Solutions

  1. Verify the server's final response format against RFC 2831; fix or report the server implementation.
  2. Capture a network trace of the raw final response to identify the malformed content and its source (proxy/middleware).
  3. Catch SaslException with ErrorCode == SaslErrorCode.IncompleteChallenge and fall back to a simpler mechanism (PLAIN/CRAM-MD5 over TLS).

Example fix

// before
client.Authenticate(uri, new SaslMechanismDigestMd5(uri, user, pass)); // server sends malformed final message
// after
try {
    client.Authenticate(uri, new SaslMechanismDigestMd5(uri, user, pass));
} catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.IncompleteChallenge) {
    client.Authenticate(uri, new SaslMechanismCramMd5(user, pass));
}
Defensive patterns

Strategy: try-catch

Validate before calling

// validate server compliance out-of-band; at runtime guard the exchange:
try { /* authenticate */ } catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.IncompleteChallenge) { /* fallback */ }

Try / catch

try {
    client.Authenticate(uri, new SaslMechanismDigestMd5(uri, user, pass));
} catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.IncompleteChallenge) {
    // server's final response was not a parseable rspauth pair
    client.Authenticate(uri, new SaslMechanismCramMd5(user, pass));
}

Prevention

When it happens

Trigger: Server's final DIGEST-MD5 message is not a parseable 'key=value' pair — e.g. empty garbage, a base64 blob, an error string, or a message missing the '=' separator.

Common situations: Non-conformant servers appending extra text after rspauth, servers sending error text where the final response belongs, protocol confusion where the server replies with a different SASL mechanism's message.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at MailKit/Security/SaslMechanismDigestMd5.cs:166

					throw new SaslException (MechanismName, SaslErrorCode.ChallengeTooLong, "Server challenge too long.");

				challenge = DigestChallenge.Parse (Encoding.UTF8.GetString (token, startIndex, length));
				encoding = challenge.Charset != null ? Encoding.UTF8 : TextEncodings.Latin1;
				cnonce ??= GenerateEntropy (15);

				response = new DigestResponse (challenge, encoding, Uri.Scheme, Uri.DnsSafeHost, AuthorizationId, Credentials.UserName, Credentials.Password, cnonce);
				state = LoginState.Final;

				return response.Encode (encoding);
			case LoginState.Final:
				if (token == null || token.Length == 0)
					throw new SaslException (MechanismName, SaslErrorCode.MissingChallenge, "Server response did not contain any authentication data.");

				var text = encoding!.GetString (token, startIndex, length);
				string? key, value;

				if (!DigestChallenge.TryParseKeyValuePair (text, out key, out value))
					throw new SaslException (MechanismName, SaslErrorCode.IncompleteChallenge, "Server response contained incomplete authentication data.");

				if (!key.Equals ("rspauth", StringComparison.OrdinalIgnoreCase))
					throw new SaslException (MechanismName, SaslErrorCode.InvalidChallenge, "Server response contained invalid data.");

				var expected = response!.ComputeHash (encoding, Credentials.Password, false);
				if (value != expected)
					throw new SaslException (MechanismName, SaslErrorCode.IncorrectHash, "Server response did not contain the expected hash.");

				IsAuthenticated = true;
				break;
			}

			return null;
		}

		/// <summary>
		/// Reset the state of the SASL mechanism.
		/// </summary>

View on GitHub (pinned to 9d3859a785)