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.
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)
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 '{localeCode}.surfaces.ordinal' defines unsupported p
- Locale '{localeCode}.surfaces.ordinal.numeric' must be a map
- Locale '{localeCode}.surfaces.ordinal.date' must be a mappin
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/732a49d2815add70.
Report an issue: GitHub.