jstedfast/MailKit · error · ArgumentException

Control characters are prohibited.

Error message

Control characters are prohibited.

What it means

SaslMechanism.SaslPrep normalizes user strings per RFC 4013 (SASLprep). Control characters (U+0000-U+001F, U+007F) are prohibited in SASLprep output, so the method throws ArgumentException when the input string contains one. The library rejects the value early rather than sending an invalid identity to the server.

Solutions

  1. Trim and strip control characters from the string before passing it to the SASL mechanism (e.g. new string(s.Where(c => !char.IsControl(c)).ToArray())).
  2. Fix the source of the string (config file, env var, DB) so it does not include control characters, e.g. use .Trim() on values read from files.
  3. Catch ArgumentException and surface a clear 'invalid username/password' message to the user.

Example fix

// before
var mech = new SaslMechanismLogin(userName); // userName contains "alice\n"
// after
var clean = new string(userName.Where(c => !char.IsControl(c)).ToArray()).Trim();
var mech = new SaslMechanismLogin(clean);
Defensive patterns

Strategy: validation

Validate before calling

static string SanitizeSaslString(string s) {
    if (s == null) throw new ArgumentNullException(nameof(s));
    var clean = new string(s.Where(c => !char.IsControl(c)).ToArray()).Trim();
    return clean.Normalize(NormalizationForm.FormKC);
}
var mech = new SaslMechanismLogin(SanitizeSaslString(userName));

Try / catch

try {
    var mech = new SaslMechanismLogin(userName);
} catch (ArgumentException) {
    // reject credential: contains control/prohibited characters
}

Prevention

When it happens

Trigger: Passing a username, authorization id, or other SASL identity containing control characters (e.g. a stray \0, \t, \r, or \n, often from config files or copy-paste) to a SaslMechanism constructor or credential property that runs SaslPrep.

Common situations: Credentials loaded from files with trailing newlines/CR, usernames read from environment variables or databases containing NUL bytes, passwords pasted from terminals with embedded control codes.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at MailKit/Security/SaslMechanism.cs:742

		public static string SaslPrep (string s)
		{
			if (s == null)
				throw new ArgumentNullException (nameof (s));

			if (s.Length == 0)
				return s;

			var builder = new StringBuilder (s.Length);
			for (int i = 0; i < s.Length; i++) {
				if (IsNonAsciiSpace (s[i])) {
					// non-ASCII space characters [StringPrep, C.1.2] that can be
					// mapped to SPACE (U+0020).
					builder.Append (' ');
				} else if (IsCommonlyMappedToNothing (s[i])) {
					// the "commonly mapped to nothing" characters [StringPrep, B.1]
					// that can be mapped to nothing.
				} else if (char.IsControl (s[i])) {
					throw new ArgumentException ("Control characters are prohibited.", nameof (s));
				} else if (IsProhibited (s, i)) {
					throw new ArgumentException ("One or more characters in the string are prohibited.", nameof (s));
				} else {
					builder.Append (s[i]);
				}
			}

			return builder.ToString ().Normalize (NormalizationForm.FormKC);
		}

		internal static string GenerateEntropy (int n)
		{
			var entropy = new byte[n];

			using (var rng = RandomNumberGenerator.Create ())
				rng.GetBytes (entropy);

			return Convert.ToBase64String (entropy);

View on GitHub (pinned to 9d3859a785)