Humanizr/Humanizer · critical · InvalidOperationException

Locale '{localeCode}.{path}.{key}' must be a non-empty strin

Error message

Locale '{localeCode}.{path}.{key}' must be a non-empty string. Omit unused sparse slots instead.

What it means

Thrown by ValidateMinuteWordValue when a clock minute slot value is a string but empty, with allowEmpty:false. The canonical schema expects unused sparse slots to be omitted entirely rather than present-but-empty, so that minute tables stay dense and unambiguous.

Source

Thrown at src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs:357

            return new SimpleYamlMapping(normalizedValues.ToImmutable());
        }

        static void ValidateMinuteWordValue(
            string localeCode,
            string path,
            string key,
            SimpleYamlValue value,
            bool allowEmpty)
        {
            if (value is not SimpleYamlScalar scalar || !scalar.IsString)
            {
                throw new InvalidOperationException(
                    $"Locale '{localeCode}.{path}.{key}' must be a string.");
            }

            if (!allowEmpty && string.IsNullOrEmpty(scalar.Value))
            {
                throw new InvalidOperationException(
                    $"Locale '{localeCode}.{path}.{key}' must be a non-empty string. Omit unused sparse slots instead.");
            }
        }

        static void ValidateNumberFormattingBlock(string localeCode, SimpleYamlMapping formatting)
        {
            foreach (var property in formatting.Values.Keys.Where(static property => property is not ("decimalSeparator" or "negativeSign" or "groupSeparator")))
            {
                throw new InvalidOperationException(
                    $"Locale '{localeCode}.surfaces.number.formatting' defines unsupported property '{property}'. Supported properties: decimalSeparator, negativeSign, groupSeparator.");
            }

            ValidateOptionalFormattingProperty(localeCode, formatting, "decimalSeparator");
            ValidateOptionalFormattingProperty(localeCode, formatting, "negativeSign");
            ValidateOptionalFormattingProperty(localeCode, formatting, "groupSeparator");

            if (formatting.Values.Count == 0)
            {

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Delete the empty minute entry entirely from surfaces.clock.minutes (the table is sparse by design).
  2. If the minute genuinely needs a word, fill in a non-empty localized string.
  3. Rebuild to confirm the locale compiles.

Example fix

# before
minutes:
  5:
  6: six minutes
# after
minutes:
  6: six minutes
Defensive patterns

Strategy: validation

Validate before calling

# Detect empty minute values before building:
# (YAML lint) ensure no 'minutes:' child is blank.
# Quick PowerShell over the locale file:
Select-String -Path src/Humanizer/Locales/<code>.yml -Pattern '^\s*\d+:\s*$'

Prevention

When it happens

Trigger: A locale YAML minute entry is written as '5:' or '5: ""' (empty value). NormalizeMinuteWordsMapping calls ValidateMinuteWordValue with allowEmpty:false for clock minutes, hitting CanonicalLocaleAuthoring.cs:355-359.

Common situations: Clearing a value while editing instead of deleting the key; copying a template that left placeholder empty strings; a merge tool留下ing blank lines for removed translations.

Related errors


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