Humanizr/Humanizer · error · InvalidOperationException

Case-aware citation phrases for '{catalog.LocaleCode}' requi

Error message

Case-aware citation phrases for '{catalog.LocaleCode}' require the duration phrase surface.

What it means

Thrown by ValidateCitationBaseDurationForms when a locale has a case-aware authored citation case (the citation realization kind is Authored with no authored units) but the top-level 'phrases' section passed to the parser is null. The citation case then has no duration phrase surface to fall back on, so the generator cannot resolve base-duration forms.

Source

Thrown at src/Humanizer.SourceGenerators/Common/DurationCaseModels.cs:903

                    $"Case overlay '{path}.multiple.forms' must explicitly define reachable '{requiredForm}' form.");
            }
        }

        static void ValidateCitationBaseDurationForms(
            DurationCaseCatalog catalog,
            SimpleYamlValue? phrasesValue,
            ImmutableArray<string> requiredMultipleForms)
        {
            if (!catalog.Realizations.TryGetValue(catalog.CitationCase, out var citation) ||
                citation.Kind != DurationCaseRealizationKind.Authored ||
                citation.Units.Count != 0)
            {
                return;
            }

            var path = $"{catalog.LocaleCode}.phrases.duration";
            var phrases = phrasesValue is null
                ? throw new InvalidOperationException(
                    $"Case-aware citation phrases for '{catalog.LocaleCode}' require the duration phrase surface.")
                : ExpectMapping(phrasesValue, $"{catalog.LocaleCode}.phrases");
            if (!phrases.TryGetValue("duration", out var durationValue))
            {
                throw new InvalidOperationException(
                    $"Case-aware citation phrases for '{catalog.LocaleCode}' require '{path}'.");
            }

            var duration = ExpectMapping(durationValue, path);
            foreach (var unitName in TimeUnits)
            {
                if (!duration.TryGetValue(unitName, out var phraseValue))
                {
                    throw new InvalidOperationException(
                        $"Case-aware citation phrases for '{catalog.LocaleCode}' require '{path}.{unitName}'.");
                }

                ValidateReachableMultipleForms(

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Ensure the locale YAML includes a 'phrases' section with at least a 'duration' sub-mapping.
  2. Pass the phrases value to DurationCaseNormalization.Parse via the phrases parameter so the citation case can validate its base-duration forms.
  3. If the locale genuinely has no duration phrases, mark the citation case as notApplicable or unsupported instead of authored.

Example fix

# before — locale file has durationCases but no phrases
phrases: ~
durationCases:
  ...
# after
phrases:
  duration:
    second:
      ...
durationCases:
  ...
Defensive patterns

Strategy: validation

Validate before calling

# Verify the locale file has a non-null 'phrases' section when durationCases is present
# python: if 'durationCases' in yaml and not yaml.get('phrases'): print('MISSING phrases')

Prevention

When it happens

Trigger: The locale YAML defines durationCases with an authored citation case (units count is 0) but does not provide a 'phrases' block at all, so phrasesValue is null when DurationCaseNormalization.Parse is called.

Common situations: A locale declares a durationCases structure with a citation case that relies on the base phrases.duration surface, but the locale file (or the caller) omits the phrases section entirely. This typically happens when a contributor splits durationCases into a separate file or partial and forgets to pass the phrases reference.

Related errors


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