{"record":{"id":"2f10e2eb932c9043","repo":"Humanizr/Humanizer","slug":"acronym-must-contain-only-letters","errorCode":null,"errorMessage":"Acronym must contain only letters.","messagePattern":"Acronym must contain only letters\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Humanizer/Inflections/Vocabulary.cs","lineNumber":43,"sourceCode":"    private static Regex LetterSRegex() => LetterSRegexGenerated();\n#else\n    private static readonly Regex LetterSRegexField = new(LetterSPattern, RegexOptions.Compiled);\n\n    private static Regex LetterSRegex() => LetterSRegexField;\n#endif\n\n    /// <summary>\n    /// Adds an acronym whose casing should be preserved when humanizing strings.\n    /// </summary>\n    /// <param name=\"acronym\">The letters in the acronym's canonical output casing, e.g. \"HTML\".</param>\n    /// <exception cref=\"ArgumentNullException\"><paramref name=\"acronym\"/> is null.</exception>\n    /// <exception cref=\"ArgumentException\"><paramref name=\"acronym\"/> is empty or contains a non-letter.</exception>\n    public void AddAcronym(string acronym)\n    {\n        ArgumentNullException.ThrowIfNull(acronym);\n        if (acronym.Length == 0 || !acronym.All(char.IsLetter))\n        {\n            throw new ArgumentException(\"Acronym must contain only letters.\", nameof(acronym));\n        }\n\n        lock (acronyms)\n        {\n            if (!acronyms.Any(rule => rule.IsFullMatch(acronym)))\n            {\n                acronyms.Add(new(\n                    $@\"\\b{Regex.Escape(acronym)}\\b\",\n                    acronym.Replace(\"$\", \"$$\"),\n                    RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled));\n            }\n        }\n    }\n\n    /// <summary>\n    /// Adds a word to the vocabulary which cannot easily be pluralized/singularized by RegEx, e.g. \"person\" and \"people\".\n    /// </summary>\n    /// <param name=\"singular\">The singular form of the irregular word, e.g. \"person\".</param>","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer/Inflections/Vocabulary.cs#L25-L61","documentation":"Thrown by Vocabulary.AddAcronym when the acronym string is null (caught first by ArgumentNullException), empty, or contains any non-letter character. The method requires a pure sequence of Unicode letters (char.IsLetter) so that the acronym can be wrapped in word-boundary regex and matched case-insensitively. The exception is an ArgumentException named 'acronym'.","triggerScenarios":"Calling Vocabularies.Default.AddAcronym(\"HTML5\") (contains a digit); AddAcronym(\"\"); AddAcronym(\"A.B\"); AddAcronym(\"C++\"). Acronyms with embedded digits, punctuation, or whitespace all fail because char.IsLetter returns false for those characters.","commonSituations":"Registering product/standard codes that include version numbers or symbols (e.g. 'ISO-9001', 'B2B', 'C#'); reading acronym lists from a file without sanitizing; treating a free-text label as an acronym.","solutions":["Strip non-letter characters before registering, or reject the input if it is not pure letters.","For acronyms that legitimately contain digits/symbols, do not use AddAcronym; instead preprocess the source string or post-process the humanized output.","Validate with acronym.All(char.IsLetter) && acronym.Length > 0 before calling AddAcronym."],"exampleFix":"// before\nVocabularies.Default.AddAcronym(\"HTML5\"); // throws\n\n// after\nvar clean = new string(\"HTML5\".Where(char.IsLetter).ToArray());\nif (clean.Length > 0)\n    Vocabularies.Default.AddAcronym(clean);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrEmpty(acronym) || !acronym.All(char.IsLetter))\n    throw new ArgumentException(\"Acronym must be non-empty letters only.\", nameof(acronym));\nVocabularies.Default.AddAcronym(acronym);","typeGuard":"static bool IsValidAcronym(string s) => !string.IsNullOrEmpty(s) && s.All(char.IsLetter);","tryCatchPattern":"try { Vocabularies.Default.AddAcronym(acronym); }\ncatch (ArgumentException) { /* skip or sanitize the acronym */ }","preventionTips":["Strip non-letters before registering, or reject impure input.","Do not treat product codes with digits/symbols as acronyms.","Sanitize acronym lists loaded from files."],"tags":["acronym","inflections","argument-validation","vocabulary"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}