Humanizr/Humanizer · error · ArgumentOutOfRangeException
gender
Error message
gender
What it means
This ArgumentOutOfRangeException is the discard arm of GetEndingForGender on UnitLeadingCompoundNumberToWordsConverter (the Luxembourgish family renderer). Unlike the terminal-ordinal converter, this switch explicitly patterns Masculine, Feminine, and Neuter — all three declared GrammaticalGender members — so the discard is only reachable via an enum value carrying an integral outside the declared range, which can only arise from an invalid cast or corrupt deserialization.
Solutions
- Validate the gender at the boundary: reject values outside the declared enum range before calling the converter.
- Map invalid values to GrammaticalGender.Masculine if graceful degradation is preferred over failing fast.
- Bind GrammaticalGender by name (string) during deserialization rather than by raw integer to prevent phantom values.
Example fix
// before
return number.ToOrdinalWords((GrammaticalGender)code, culture);
// after
var gender = Enum.IsDefined(typeof(GrammaticalGender), code)
? (GrammaticalGender)code
: GrammaticalGender.Masculine;
return number.ToOrdinalWords(gender, culture); Defensive patterns
Strategy: validation
Validate before calling
bool IsValidGender(GrammaticalGender gender) =>
gender is GrammaticalGender.Masculine
or GrammaticalGender.Feminine
or GrammaticalGender.Neuter; Type guard
static bool IsDefinedGender(GrammaticalGender gender) =>
Enum.IsDefined(typeof(GrammaticalGender), gender); Try / catch
try
{
return number.ToOrdinalWords(gender, culture);
}
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "gender")
{
return number.ToOrdinalWords(GrammaticalGender.Masculine, culture);
} Prevention
- Validate GrammaticalGender at the boundary where external data enters your code.
- Prefer named enum binding over integer binding in deserialization.
- Use Enum.IsDefined for any gender sourced from an integer or dynamic type.
- Coerce invalid values to Masculine for graceful degradation where the business allows it.
When it happens
Trigger: Calling ConvertToOrdinal(number, gender) on a locale backed by UnitLeadingCompoundNumberToWordsConverter with a GrammaticalGender value that is not Masculine, Feminine, or Neuter (produced by an unchecked cast or unvalidated external input).
Common situations: Forwarding a gender from a loosely typed integration layer (database int, JSON number, dynamic object) into the ordinal API; unit tests using reflection-constructed enum values; deserialization frameworks that bind enums by integer.
Related errors
- gender
- gender
- Locale ' .surfaces.ordinal.date' must be a mapping, not a…
- Locale ' .surfaces.ordinal.dateOnly' must be a mapping, not…
- Locale ' .surfaces.ordinal' defines unsupported property '…
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/732a49d2815add70.
Report an issue: GitHub.
Appendix: source
Thrown at src/Humanizer/Localisation/NumberToWords/UnitLeadingCompoundNumberToWordsConverter.cs:258
string GetCompoundUnit(int number) => profile.CompoundUnitsMap[number];
// The tens joiner itself may need a transform such as the Eifeler rule depending on the next word.
string GetTensJoiner(string nextWord) =>
profile.TensJoinerTransform switch
{
CompoundTensJoinerTransform.None => profile.TensJoiner,
CompoundTensJoinerTransform.Eifeler => EifelerRule.ApplyIfNeeded(profile.TensJoiner, nextWord),
_ => throw new InvalidOperationException("Unknown unit-leading-compound tens joiner transform.")
};
string GetEndingForGender(GrammaticalGender gender) =>
gender switch
{
GrammaticalGender.Masculine => profile.MasculineOrdinalEnding,
GrammaticalGender.Feminine => profile.FeminineOrdinalEnding,
GrammaticalGender.Neuter => profile.NeuterOrdinalEnding,
_ => throw new ArgumentOutOfRangeException(nameof(gender))
};
}
/// <summary>
/// Immutable generated profile for <see cref="UnitLeadingCompoundNumberToWordsConverter"/>.
/// </summary>
/// <param name="zeroWord">The cardinal zero word.</param>
/// <param name="minusWord">The word used to prefix negative values.</param>
/// <param name="masculineOne">The masculine form of one.</param>
/// <param name="feminineOne">The feminine form of one.</param>
/// <param name="neuterOne">The neuter form of one.</param>
/// <param name="feminineTwo">The optional feminine form of two.</param>
/// <param name="tensJoiner">The base joiner inserted between the unit and tens stem.</param>
/// <param name="tensJoinerTransform">The transform applied to <paramref name="tensJoiner"/> before emission.</param>
/// <param name="ordinalStemSuffix">The shared ordinal stem suffix appended before the gender ending.</param>
/// <param name="masculineOrdinalEnding">The masculine ordinal ending.</param>
/// <param name="feminineOrdinalEnding">The feminine ordinal ending.</param>
/// <param name="neuterOrdinalEnding">The neuter ordinal ending.</param>View on GitHub (pinned to ffc2b77c0f)