jstedfast/MailKit · error · SaslException

MissingChallenge

MissingChallenge

Error message

Server response did not contain any authentication data.

What it means

In the Final state of DIGEST-MD5, the server must send a final response containing at least the 'rspauth' verification value. SaslMechanismDigestMd5.Challenge throws SaslException with code SaslErrorCode.MissingChallenge when the final token is null or empty, meaning the server sent no authentication data.

Solutions

  1. Verify the server actually implements the full DIGEST-MD5 final step; if not, use a different mechanism (SCRAM, CRAM-MD5, PLAIN over TLS).
  2. Check for connection drops/truncation (TLS termination, proxy) and fix the network path.
  3. Catch SaslException with ErrorCode == SaslErrorCode.MissingChallenge and retry with a fallback mechanism or fail with a clear server-compatibility message.

Example fix

// before
client.Authenticate(uri, new SaslMechanismDigestMd5(uri, user, pass)); // server omits final rspauth
// after
try {
    client.Authenticate(uri, new SaslMechanismDigestMd5(uri, user, pass));
} catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.MissingChallenge) {
    client.Authenticate(uri, new SaslMechanismPlain(user, pass)); // over TLS
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify server implements full RFC 2831 final step before relying on DIGEST-MD5
// ensure the connection is not truncated by proxies/TLS termination

Try / catch

try {
    client.Authenticate(uri, new SaslMechanismDigestMd5(uri, user, pass));
} catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.MissingChallenge) {
    // server omitted the final rspauth response; fall back
    client.Authenticate(uri, new SaslMechanismPlain(user, pass));
}

Prevention

When it happens

Trigger: Server closes the exchange without a final DIGEST-MD5 response, or passes a zero-length buffer to Challenge while the mechanism is in LoginState.Final.

Common situations: Server implementations that skip the RFC 2831 final step, dropped connections mid-handshake, proxies that truncate the SASL exchange.

Understand the failure class

Background: "empty response", "returned no data", "empty embeddings": what HTTP 200-with-empty-body errors mean across libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at MailKit/Security/SaslMechanismDigestMd5.cs:160

			switch (state) {
			case LoginState.Auth:
				if (token == null)
					throw new NotSupportedException ("DIGEST-MD5 does not support SASL-IR.");

				if (token.Length > 2048)
					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;
			}

View on GitHub (pinned to 9d3859a785)