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

  1. Report the locale bug — membership suffix data is incomplete.
  2. Switch to a locale/version with complete membership suffix data.
  3. 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

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


AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13). Data as JSON: /api/errors/6dd94cd39ea42daf. Report an issue: GitHub.