Humanizr/Humanizer · error · InvalidOperationException
Harmony-ordinal membership suffix data is incomplete.
Error message
Harmony-ordinal membership suffix data is incomplete.
What it means
The FinalCharacterMembership ordinal strategy needs both a non-empty SecondOrdinalSuffixCharacters set and exactly a 2-element OrdinalSuffixPair. The profile supplied incomplete data (null/empty character set, or a pair whose length is not 2). Profile-data defect fired during ConvertToOrdinal.
Source
Thrown at src/Humanizer/Localisation/NumberToWords/HarmonyOrdinalNumberToWordsConverter.cs:222
break;
}
}
word = ApplyHarmonyStemAdjustments(word, suffixFoundOnLastVowel);
return word + suffix;
}
// Some locales split between two ordinal suffixes by final-character membership rather than by
// the last vowel. That alternative stays structural because the deciding character set and the
// suffix pair still come from generated data.
/// <summary>
/// Appends the ordinal suffix selected by final-character membership.
/// </summary>
static string AppendMembershipOrdinalSuffix(string word, string? secondOrdinalSuffixCharacters, string[] ordinalSuffixPair)
{
if (string.IsNullOrEmpty(secondOrdinalSuffixCharacters) || ordinalSuffixPair.Length != 2)
{
throw new InvalidOperationException("Harmony-ordinal membership suffix data is incomplete.");
}
// Membership-based locales still keep the suffix choice data-driven; the final character
// set selects which of the two generated suffixes should be used.
var suffixIndex = secondOrdinalSuffixCharacters.Contains(word[^1]) ? 1 : 0;
return word + ordinalSuffixPair[suffixIndex];
}
// Harmony adjustments operate on the already-rendered cardinal word so the family can model
// softening and terminal-vowel dropping without duplicating the full cardinal renderer.
/// <summary>
/// Applies the locale's stem adjustments before a harmony suffix is appended.
/// </summary>
string ApplyHarmonyStemAdjustments(string word, bool suffixFoundOnLastVowel)
{
// The stem edits happen before the suffix is appended so the same base word can support
// softening and terminal-vowel loss without duplicating the cardinal renderer.
if (profile.SoftenTerminalTBeforeSuffix && word[^1] == 't')View on GitHub (pinned to ffc2b77c0f)
Solutions
- Report the locale bug — membership suffix data is incomplete.
- Switch to a locale/version with complete membership suffix data.
- If authoring, provide both secondOrdinalSuffixCharacters and a 2-element ordinalSuffixPair.
Defensive patterns
Strategy: try-catch
Validate before calling
// Membership suffix data is internal; no public pre-check. Catch InvalidOperationException from // ConvertToOrdinal referencing the membership suffix message.
Try / catch
string ordinal;
try
{
ordinal = number.ToOrdinalWords(culture);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("membership suffix data is incomplete"))
{
ordinal = number.ToOrdinalWords(CultureInfo.InvariantCulture);
} Prevention
- Smoke-test ordinal conversion for each Turkic locale after upgrades.
- Report incomplete membership suffix data upstream.
- Fall back to a verified locale when ordinal data is incomplete.
When it happens
Trigger: number.ToOrdinalWords(<turkic culture>) where OrdinalSuffixStrategy == FinalCharacterMembership and secondOrdinalSuffixCharacters is null/empty or ordinalSuffixPair.Length != 2.
Common situations: Locale YAML set the membership strategy but left secondOrdinalSuffixCharacters empty or ordinalSuffixPair with the wrong arity.
Related errors
- Unsupported harmony-ordinal suffix strategy.
- Harmony-ordinal suffix data is missing.
- 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/6dd94cd39ea42daf.
Report an issue: GitHub.