{"record":{"id":"6006a902b1507a2a","repo":"jstedfast/MailKit","slug":"missingchallenge","errorCode":"MissingChallenge","errorMessage":"Server response did not contain any authentication data.","messagePattern":"Server response did not contain any authentication data\\.","errorType":"error_code","errorClass":"SaslException","httpStatus":null,"severity":"error","filePath":"MailKit/Security/SaslMechanismDigestMd5.cs","lineNumber":160,"sourceCode":"\t\t\tswitch (state) {\n\t\t\tcase LoginState.Auth:\n\t\t\t\tif (token == null)\n\t\t\t\t\tthrow new NotSupportedException (\"DIGEST-MD5 does not support SASL-IR.\");\n\n\t\t\t\tif (token.Length > 2048)\n\t\t\t\t\tthrow new SaslException (MechanismName, SaslErrorCode.ChallengeTooLong, \"Server challenge too long.\");\n\n\t\t\t\tchallenge = DigestChallenge.Parse (Encoding.UTF8.GetString (token, startIndex, length));\n\t\t\t\tencoding = challenge.Charset != null ? Encoding.UTF8 : TextEncodings.Latin1;\n\t\t\t\tcnonce ??= GenerateEntropy (15);\n\n\t\t\t\tresponse = new DigestResponse (challenge, encoding, Uri.Scheme, Uri.DnsSafeHost, AuthorizationId, Credentials.UserName, Credentials.Password, cnonce);\n\t\t\t\tstate = LoginState.Final;\n\n\t\t\t\treturn response.Encode (encoding);\n\t\t\tcase LoginState.Final:\n\t\t\t\tif (token == null || token.Length == 0)\n\t\t\t\t\tthrow new SaslException (MechanismName, SaslErrorCode.MissingChallenge, \"Server response did not contain any authentication data.\");\n\n\t\t\t\tvar text = encoding!.GetString (token, startIndex, length);\n\t\t\t\tstring? key, value;\n\n\t\t\t\tif (!DigestChallenge.TryParseKeyValuePair (text, out key, out value))\n\t\t\t\t\tthrow new SaslException (MechanismName, SaslErrorCode.IncompleteChallenge, \"Server response contained incomplete authentication data.\");\n\n\t\t\t\tif (!key.Equals (\"rspauth\", StringComparison.OrdinalIgnoreCase))\n\t\t\t\t\tthrow new SaslException (MechanismName, SaslErrorCode.InvalidChallenge, \"Server response contained invalid data.\");\n\n\t\t\t\tvar expected = response!.ComputeHash (encoding, Credentials.Password, false);\n\t\t\t\tif (value != expected)\n\t\t\t\t\tthrow new SaslException (MechanismName, SaslErrorCode.IncorrectHash, \"Server response did not contain the expected hash.\");\n\n\t\t\t\tIsAuthenticated = true;\n\t\t\t\tbreak;\n\t\t\t}\n","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/jstedfast/MailKit/blob/9d3859a7855e3e17582c07fd01972b8e262bf176/MailKit/Security/SaslMechanismDigestMd5.cs#L142-L178","documentation":"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.","triggerScenarios":"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.","commonSituations":"Server implementations that skip the RFC 2831 final step, dropped connections mid-handshake, proxies that truncate the SASL exchange.","solutions":["Verify the server actually implements the full DIGEST-MD5 final step; if not, use a different mechanism (SCRAM, CRAM-MD5, PLAIN over TLS).","Check for connection drops/truncation (TLS termination, proxy) and fix the network path.","Catch SaslException with ErrorCode == SaslErrorCode.MissingChallenge and retry with a fallback mechanism or fail with a clear server-compatibility message."],"exampleFix":"// before\nclient.Authenticate(uri, new SaslMechanismDigestMd5(uri, user, pass)); // server omits final rspauth\n// after\ntry {\n    client.Authenticate(uri, new SaslMechanismDigestMd5(uri, user, pass));\n} catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.MissingChallenge) {\n    client.Authenticate(uri, new SaslMechanismPlain(user, pass)); // over TLS\n}","handlingStrategy":"try-catch","validationCode":"// verify server implements full RFC 2831 final step before relying on DIGEST-MD5\n// ensure the connection is not truncated by proxies/TLS termination","typeGuard":null,"tryCatchPattern":"try {\n    client.Authenticate(uri, new SaslMechanismDigestMd5(uri, user, pass));\n} catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.MissingChallenge) {\n    // server omitted the final rspauth response; fall back\n    client.Authenticate(uri, new SaslMechanismPlain(user, pass));\n}","preventionTips":["Prefer SCRAM-SHA-256 over legacy DIGEST-MD5 for modern servers","Use TLS so intermediaries cannot truncate or alter the SASL exchange","Match on SaslErrorCode for precise fallback handling"],"tags":["sasl","digest-md5","server-compatibility","empty-response"],"backgroundTag":"empty-api-response","analyzedSha":"9d3859a7855e3e17582c07fd01972b8e262bf176","analyzedAt":"2026-09-15T15:46:11.592Z","contentChangedAt":"2026-09-15T15:46:11.592Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}