{"record":{"id":"55e6c1d95897cfb2","repo":"Humanizr/Humanizer","slug":"indian-scale-form-number-profiles-require-a-scale","errorCode":null,"errorMessage":"Indian scale-form number profiles require a scale value no greater than the dense unit map range.","messagePattern":"Indian scale-form number profiles require a scale value no greater than the dense unit map range\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer/Localisation/NumberToWords/IndianScaleFormNumberToWordsConverter.cs","lineNumber":94,"sourceCode":"            var scaleValue = (ulong)scale.Value;\n            var count = remainder / scaleValue;\n            if (count == 0)\n            {\n                continue;\n            }\n\n            remainder %= scaleValue;\n            parts.Add(FormatScale(scale, count, remainder > 0));\n        }\n\n        if (remainder > 0)\n        {\n            parts.Add(ConvertPositive(remainder));\n        }\n\n        if (parts.Count == 0)\n        {\n            throw new InvalidOperationException(\"Indian scale-form number profiles require a scale value no greater than the dense unit map range.\");\n        }\n\n        return string.Join(\" \", parts);\n    }\n\n    string FormatScale(IndianScaleForm scale, ulong count, bool hasRemainder)\n    {\n        var scaleWord = count == 1\n            ? hasRemainder ? scale.SingularWithRemainder : scale.Singular\n            : hasRemainder ? scale.PluralWithRemainder : scale.Plural;\n\n        return count == 1 && scale.OmitOne\n            ? scaleWord\n            : ConvertPositive(count) + \" \" + scaleWord;\n    }\n}\n\n/// <summary>","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer/Localisation/NumberToWords/IndianScaleFormNumberToWordsConverter.cs#L76-L112","documentation":"ConvertPositive decomposed the number against all scale rows and the dense unit map but produced zero parts with a remainder, meaning the scales don't cover the value's magnitude and it fell outside the dense map. The guard fires (rather than emitting an empty string) when the smallest scale value exceeds the dense unit map range, leaving an uncovered gap in the Indian scale-form profile.","triggerScenarios":"value.ToWords(<indian-scale culture>) for a value that sits in the gap between the dense unit map ceiling and the smallest scale, or beyond all scales, due to a misconfigured profile (smallest scale Value > DenseUnitsMap.Length, or scales that don't chain down to the dense range).","commonSituations":"Locale profile where scales start above where dense words end; scales that don't descend to 100; a source-generator gap.","solutions":["Report the locale/profile bug — the scale chain has a gap above the dense unit map.","Use a locale with a consistent scale chain.","If authoring, ensure the smallest scale Value <= DenseUnitsMap.Length and scales descend to the dense range."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Scale/dense-map coverage is internal. No public pre-check; wrap Convert and fall back.","typeGuard":null,"tryCatchPattern":"string words;\ntry\n{\n    words = value.ToWords(culture);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"scale value no greater than the dense unit map range\"))\n{\n    words = value.ToWords(CultureInfo.InvariantCulture);\n}","preventionTips":["Bound numeric inputs before localizing for Indian scale-form locales.","Report scale-chain gaps upstream.","Smoke-test a spread of magnitudes per locale after upgrades."],"tags":["number-to-words","profile-data","localization"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}