{"record":{"id":"39141b28be3ca6c0","repo":"Humanizr/Humanizer","slug":"unrecognized-number-word-unrecognizedword","errorCode":null,"errorMessage":"Unrecognized number word: {unrecognizedWord}","messagePattern":"Unrecognized number word: (.+?)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Humanizer/Localisation/WordsToNumber/CompoundScaleWordsToNumberConverter.cs","lineNumber":26,"sourceCode":"/// - optional ordinal forms derived from either explicit YAML or a generated number-to-words bridge\n///\n/// The parser normalizes the input, strips a configured negative prefix, then resolves either an\n/// exact ordinal token or a cardinal phrase assembled from token groups and scale multipliers.\n/// The end result should be the numeric value the locale phrase denotes, not merely a best-effort\n/// token sum.\n/// </summary>\ninternal class CompoundScaleWordsToNumberConverter(CompoundScaleWordsToNumberProfile profile) : GenderlessWordsToNumberConverter\n{\n    const int MaximumParseDepth = 128;\n\n    readonly CompoundScaleWordsToNumberProfile profile = profile;\n\n    /// <inheritdoc />\n    public override long Convert(string words)\n    {\n        if (!TryConvert(words, out var parsedValue, out var unrecognizedWord))\n        {\n            throw new ArgumentException($\"Unrecognized number word: {unrecognizedWord}\");\n        }\n\n        return parsedValue;\n    }\n\n    /// <inheritdoc />\n    public override bool TryConvert(string words, out long parsedValue) =>\n        TryConvert(words, out parsedValue, out _);\n\n    /// <inheritdoc />\n    public override bool TryConvert(string words, out long parsedValue, out string? unrecognizedWord)\n    {\n        if (string.IsNullOrWhiteSpace(words))\n        {\n            throw new ArgumentException(\"Input words cannot be empty.\");\n        }\n\n        var normalized = Normalize(words);","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer/Localisation/WordsToNumber/CompoundScaleWordsToNumberConverter.cs#L8-L44","documentation":"This ArgumentException is thrown by CompoundScaleWordsToNumberConverter.Convert (the throwing entry point) when TryConvert returns false. TryConvert returns false when the normalized input phrase contains a token that is not in the locale's cardinal map, ordinal map, tens stems, or large-scale words. The unrecognized word is included in the message for diagnostics. This converter is used by locales that compose cardinals from direct tokens, optional tens stems, and explicit scale words (thousand, million, etc.).","triggerScenarios":"Calling \"words\".ToNumber(culture) for a compound-scale locale with a phrase that includes a misspelled word, a word from a different language, punctuation the normalizer does not strip, or a number outside the locale's authored vocabulary.","commonSituations":"User-typed free-text input fed directly into ToNumber without pre-validation; copy-paste from a source that includes smart quotes or Unicode punctuation not handled by the normalizer; locale mismatch (passing English words to a non-English culture); using an ordinal or large-scale word the locale YAML did not author.","solutions":["Use TryToNumber(words, out value, culture, out unrecognizedWord) instead of ToNumber so unrecognized input returns false instead of throwing.","Pre-validate the phrase against the locale's expected vocabulary or constrain user input to known number words.","Check that the CultureInfo passed matches the language of the words; feeding English words to a non-English culture always fails.","Normalize user input (strip unexpected punctuation, correct casing) before parsing if the source is untrusted."],"exampleFix":"// before\nlong value = \"twnty\".ToNumber(new CultureInfo(\"en\"));\n\n// after\nif (!\"twnty\".TryToNumber(out var value, new CultureInfo(\"en\"), out var bad))\n    Console.WriteLine($\"Unrecognized: {bad}\");","handlingStrategy":"try-catch","validationCode":"// Use the non-throwing API instead\nbool canParse = words.TryToNumber(out var value, culture, out var unrecognized);\nif (!canParse)\n    Console.WriteLine($\"Cannot parse: unknown token '{unrecognized}'\");","typeGuard":"// Check if the phrase is likely parseable by sampling known tokens\nstatic bool LooksLikeNumberWords(string words, CultureInfo culture)\n{\n    if (string.IsNullOrWhiteSpace(words)) return false;\n    return words.TryToNumber(out _, culture, out _);\n}","tryCatchPattern":"try\n{\n    return words.ToNumber(culture);\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"Unrecognized number word\"))\n{\n    // Log and handle the unrecognized input\n    return 0;\n}","preventionTips":["Prefer TryToNumber over ToNumber for any input that may be user-generated or untrusted.","Pre-validate input: check that the culture matches the language of the words.","Inspect the unrecognizedWord from TryToNumber to provide actionable feedback.","Normalize input (strip unexpected punctuation, fix casing) before parsing."],"tags":["argumentexception","words-to-number","compound-scale","unrecognized-word","parsing"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}