Humanizr/Humanizer · error · InvalidOperationException
Unsupported harmony-ordinal suffix strategy.
Error message
Unsupported harmony-ordinal suffix strategy.
What it means
ConvertToOrdinal's switch over profile.OrdinalSuffixStrategy hit its default arm — the profile declared a HarmonyOrdinalSuffixStrategy value the converter does not handle. This is a profile-data / source-generator defect, not user input. It fires during ToOrdinalWords() for a Turkic locale whose ordinal strategy is out of range.
Source
Thrown at src/Humanizer/Localisation/NumberToWords/HarmonyOrdinalNumberToWordsConverter.cs:148
value >= 0 ? (ulong)value : unchecked((ulong)(-(value + 1)) + 1);
/// <summary>
/// Converts the given value using the locale's harmony-based ordinal rules.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <returns>The localized ordinal words for <paramref name="number"/>.</returns>
public override string ConvertToOrdinal(int number)
{
// Ordinals are the cardinal form plus a suffix strategy chosen by the generated profile.
var word = Convert(number);
return profile.OrdinalSuffixStrategy switch
{
HarmonyOrdinalSuffixStrategy.LastVowelMap => AppendHarmonySuffix(word, profile.OrdinalSuffixes, useTerminalVowelOrdinalSuffixes: true),
HarmonyOrdinalSuffixStrategy.FinalCharacterMembership => AppendMembershipOrdinalSuffix(
word,
profile.SecondOrdinalSuffixCharacters,
profile.OrdinalSuffixPair),
_ => throw new InvalidOperationException("Unsupported harmony-ordinal suffix strategy.")
};
}
/// <summary>
/// Converts the given value to a tuple form, using either a named tuple or harmony suffixes.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <returns>The localized tuple words for <paramref name="number"/>.</returns>
public override string ConvertToTuple(int number)
{
// Exact tuple names win first; only unknown tuples fall back to harmony-suffix rendering.
if (profile.NamedTuples is not null && profile.NamedTuples.TryGetValue(number, out var namedTuple))
{
return namedTuple;
}
if (profile.TupleSuffixes is null)
{View on GitHub (pinned to ffc2b77c0f)
Solutions
- Report the locale + version as a library/locale-data bug.
- Use a Humanizer version where profile data and the switch agree.
- If authoring a locale, set OrdinalSuffixStrategy to LastVowelMap or FinalCharacterMembership.
Defensive patterns
Strategy: try-catch
Validate before calling
// OrdinalSuffixStrategy is internal; callers cannot pre-validate. Catch InvalidOperationException // from ConvertToOrdinal and fall back to a known-good locale.
Try / catch
string ordinal;
try
{
ordinal = number.ToOrdinalWords(culture);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("harmony-ordinal suffix strategy"))
{
ordinal = number.ToOrdinalWords(CultureInfo.InvariantCulture);
} Prevention
- Smoke-test ToOrdinalWords for each Turkic locale after a Humanizer upgrade.
- Pin a consistent Humanizer version.
- Report ordinal-strategy defects upstream.
When it happens
Trigger: number.ToOrdinalWords(new CultureInfo(<turkic culture>)) where profile.OrdinalSuffixStrategy is neither LastVowelMap nor FinalCharacterMembership.
Common situations: Version mismatch where a new enum member was added without a corresponding switch case; hand-authored locale data with an invalid strategy value.
Related errors
- Harmony-ordinal suffix data is missing.
- Harmony-ordinal membership suffix data is incomplete.
- Unsupported conjunctional-scale strategy.
- The scale profile must include the thousand row.
- Indian scale-form number profiles require a scale value no g
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/a1e1bcad9f952e51.
Report an issue: GitHub.