jstedfast/MailKit · error · InvalidOperationException
Operation is not valid due to the current state of the…
Error message
Operation is not valid due to the current state of the object.
What it means
DIGEST-MD5 (RFC 2831) binds the digest computation to a URI (service type and host, e.g. 'imap/mail.example.com'). SaslMechanismDigestMd5.Challenge throws InvalidOperationException when the mechanism's Uri property is null because the digest response cannot be constructed without it.
Solutions
- Use the SaslMechanismDigestMd5(Uri uri, ...) constructor overload that supplies the service URI instead of the bare credentials constructor.
- Authenticate through SmtpClient/ImapClient/Pop3Client, which automatically set the mechanism's Uri from the server being connected to.
- Null-check Uri before calling Challenge in custom SASL drivers and construct the mechanism with the correct uri (scheme + host of the service).
Example fix
// before
var mech = new SaslMechanismDigestMd5(user, pass); // Uri is null
// after
var mech = new SaslMechanismDigestMd5(new Uri("imap://mail.example.com"), user, pass); Defensive patterns
Strategy: validation
Validate before calling
if (mech.Uri == null)
throw new InvalidOperationException("DIGEST-MD5 requires a service URI; use the (Uri, user, pass) constructor."); Try / catch
try {
client.Authenticate(uri, mech);
} catch (InvalidOperationException) {
mech = new SaslMechanismDigestMd5(uri, user, pass);
client.Authenticate(uri, mech);
} Prevention
- Always construct SaslMechanismDigestMd5 with the Uri overload
- Authenticate via SmtpClient/ImapClient/Pop3Client so the Uri is set automatically
- Don't reuse mechanism instances created without a Uri
When it happens
Trigger: Instantiating SaslMechanismDigestMd5 and starting authentication without a Uri (using a constructor/property path that never sets it), then calling Challenge (directly or via Authenticate).
Common situations: Using a mechanism instance across contexts where the Uri was never provided, constructing the mechanism manually for a custom SASL host instead of via SmtpClient/ImapClient (which set the Uri from the connection).
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- DIGEST-MD5 does not support SASL-IR.
- ChallengeTooLong
- MissingChallenge
- IncompleteChallenge
- InvalidChallenge
AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15).
Data as JSON: /api/errors/1b9f8c2ce79a4f0f.
Report an issue: GitHub.
Appendix: source
Thrown at MailKit/Security/SaslMechanismDigestMd5.cs:140
/// <param name="startIndex">The index into the token specifying where the server's challenge begins.</param>
/// <param name="length">The length of the server's challenge.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.NotSupportedException">
/// The SASL mechanism does not support SASL-IR.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="SaslException">
/// An error has occurred while parsing the server's challenge token.
/// </exception>
protected override byte[]? Challenge (byte[]? token, int startIndex, int length, CancellationToken cancellationToken)
{
if (IsAuthenticated)
return null;
if (Uri is null)
throw new InvalidOperationException ();
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:View on GitHub (pinned to 9d3859a785)