jstedfast/MailKit · error · ArgumentNullException

userName

Error message

userName

What it means

The NtlmAuthenticateMessage constructor throws ArgumentNullException when userName is null. The username is embedded in the Type3 AUTHENTICATE message, so it must be provided (an empty string is acceptable, null is not).

Solutions

  1. Pass a non-null userName (use string.Empty for anonymous/blank usernames).
  2. Validate credentials are populated before starting the NTLM handshake.
  3. Fix the config/env source so the username is loaded (e.g. check for missing settings).

Example fix

// before
var auth = new NtlmAuthenticateMessage(negotiate, challenge, null, pass, domain, ws);
// after
var auth = new NtlmAuthenticateMessage(negotiate, challenge, userName ?? string.Empty, pass, domain, ws);
Defensive patterns

Strategy: validation

Validate before calling

if (userName == null) throw new InvalidOperationException("NTLM username is not configured.");
var auth = new NtlmAuthenticateMessage(negotiate, challenge, userName, password, domain, workstation);

Type guard

static bool HasUserName(string userName) => !string.IsNullOrEmpty(userName);

Try / catch

try {
	auth = new NtlmAuthenticateMessage(negotiate, challenge, userName, password, domain, workstation);
} catch (ArgumentNullException ex) when (ex.ParamName == "userName") {
	// prompt for or reload credentials
	userName = LoadConfiguredUserName() ?? string.Empty;
}

Prevention

When it happens

Trigger: Calling new NtlmAuthenticateMessage(negotiate, challenge, null, password, domain, workstation), usually from unset credential variables or config fields.

Common situations: Credentials read from configuration/environment that were never populated; anonymous-auth code paths passing null instead of string.Empty.

Related errors


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

Appendix: source

Thrown at MailKit/Security/Ntlm/NtlmAuthenticateMessage.cs:51

namespace MailKit.Security.Ntlm {
	class NtlmAuthenticateMessage : NtlmMessageBase
	{
		static readonly byte[] Z16 = new byte[16];

		readonly NtlmNegotiateMessage? negotiate;
		readonly NtlmChallengeMessage? challenge;
		byte[] clientChallenge;

		public NtlmAuthenticateMessage (NtlmNegotiateMessage negotiate, NtlmChallengeMessage challenge, string userName, string password, string domain, string workstation) : base (3)
		{
			if (negotiate == null)
				throw new ArgumentNullException (nameof (negotiate));

			if (challenge == null)
				throw new ArgumentNullException (nameof (challenge));

			if (userName == null)
				throw new ArgumentNullException (nameof (userName));

			if (password == null)
				throw new ArgumentNullException (nameof (password));

			clientChallenge = NtlmUtils.NONCE (8);
			this.negotiate = negotiate;
			this.challenge = challenge;

			if (!string.IsNullOrEmpty (domain)) {
				Domain = domain;
			} else if ((challenge.Flags & NtlmFlags.TargetTypeDomain) != 0) {
				// The server is domain-joined, so the TargetName will be the domain.
				Domain = challenge.TargetName ?? string.Empty;
			} else if (challenge.TargetInfo != null) {
				// The server is not domain-joined, so the TargetName will be the machine name of the server.
				Domain = challenge.TargetInfo.DomainName ?? string.Empty;
			} else {
				Domain = string.Empty;

View on GitHub (pinned to 9d3859a785)