jstedfast/MailKit · error · SaslException

MissingChallenge

MissingChallenge

Error message

Server response did not contain any authentication data.

What it means

SCRAM (SCRAM-SHA-1/256/512) is a multi-step exchange: after the client-first message the server must return a server-first message containing salt, nonce, and iteration count. If Challenge() is entered in the Final state with a null token, SaslException with SaslErrorCode.MissingChallenge is thrown because no server-first data arrived.

Solutions

  1. Log the server's exact reply to the client-first message; an empty reply usually means the server rejected the mechanism
  2. Verify the server supports the specific SCRAM hash (SCRAM-SHA-1 vs SCRAM-SHA-256) via its advertised AUTH mechanisms
  3. Authenticate over TLS with PLAIN if the server's SCRAM support is broken
  4. Catch SaslException with ErrorCode == SaslErrorCode.MissingChallenge and fall back to another mechanism

Example fix

// before
client.Authenticate (new SaslMechanismScramSha256 ("user", "pass"));
// after
try {
    client.Authenticate (new SaslMechanismScramSha256 ("user", "pass"));
} catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.MissingChallenge) {
    client.Authenticate (new SaslMechanismPlain ("user", "pass")); // over TLS
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Check the mechanism is advertised before use:
if (!client.AuthenticationMechanisms.Contains ("SCRAM-SHA-256"))
    useFallback = true;

Try / catch

try {
    client.Authenticate (new SaslMechanismScramSha256 ("user", "pass"));
} catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.MissingChallenge) {
    // empty server-first message: fall back to PLAIN over TLS
}

Prevention

When it happens

Trigger: Calling Challenge() on a SaslMechanismScramSha1/Sha256/Sha512 when state == LoginState.Final and token is null — the server sent no data in response to the client-first message.

Common situations: Servers that advertise SCRAM but fail mid-exchange, protocol layers delivering an empty continuation, or IMAP/SMTP servers rejecting the mechanism with an empty continuation instead of an error tag.

Understand the failure class

Related errors


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

Appendix: source

Thrown at MailKit/Security/SaslMechanismScramBase.cs:337

				//
				// Based on this, we attempt to use "tls-server-end-point" instead of "tls-unique" when available.
				if (SupportsChannelBinding) {
					if (TryGetChannelBindingToken (ChannelBindingKind.Endpoint, out channelBindingToken)) {
						channelBindingKind = ChannelBindingKind.Endpoint;
					} else if (TryGetChannelBindingToken (ChannelBindingKind.Unique, out channelBindingToken)) {
						channelBindingKind = ChannelBindingKind.Unique;
					} else {
						channelBindingKind = ChannelBindingKind.Unknown;
					}
				}

				input = GetChannelBindingInput (channelBindingKind, AuthorizationId);
				response = Encoding.UTF8.GetBytes (input + client);
				state = LoginState.Final;
				break;
			case LoginState.Final:
				if (token == null)
					throw new SaslException (MechanismName, SaslErrorCode.MissingChallenge, "Server response did not contain any authentication data.");

				server = Encoding.UTF8.GetString (token, startIndex, length);
				var tokens = ParseServerChallenge (server);
				string? salt, nonce, iterations;
				int count;

				if (!tokens.TryGetValue ('s', out salt))
					throw new SaslException (MechanismName, SaslErrorCode.IncompleteChallenge, "Challenge did not contain a salt.");

				if (!tokens.TryGetValue ('r', out nonce))
					throw new SaslException (MechanismName, SaslErrorCode.IncompleteChallenge, "Challenge did not contain a nonce.");

				if (!tokens.TryGetValue ('i', out iterations))
					throw new SaslException (MechanismName, SaslErrorCode.IncompleteChallenge, "Challenge did not contain an iteration count.");

				if (!nonce.StartsWith (cnonce!, StringComparison.Ordinal))
					throw new SaslException (MechanismName, SaslErrorCode.InvalidChallenge, "Challenge contained an invalid nonce.");

View on GitHub (pinned to 9d3859a785)