Humanizr/Humanizer · error · InvalidOperationException

Property '{propertyName}' must be a mapping.

Error message

Property '{propertyName}' must be a mapping.

What it means

Thrown by CreateTerminalContinuingStringArrayExpression when an ordinal pair that resolved as a JSON object lacks the required shape. The generator reached this branch because the parent ordinal value was a mapping, but the inner value is not itself a mapping (it is a scalar or array), so it cannot read the 'terminal' and 'continuing' sub-keys.

Source

Thrown at src/Humanizer.SourceGenerators/Common/GenerationHelpers.cs:1022

            OptionalStringValue("countWordFormNextWord"));

    static string CreateUnitLeadingCompoundOrdinalPairExpression(JsonElement element, string propertyName)
    {
        return !element.TryGetProperty(propertyName, out var property)
            ? throw new InvalidOperationException($"Missing required property '{propertyName}'.")
            : property.ValueKind switch
            {
                JsonValueKind.String => "new string[] { " + QuoteLiteral(property.GetString()!) + ", " + QuoteLiteral(property.GetString()!) + " }",
                JsonValueKind.Array => CreateStringArrayExpression(property),
                JsonValueKind.Object => CreateTerminalContinuingStringArrayExpression(property, propertyName),
                _ => throw new InvalidOperationException($"Property '{propertyName}' must be a string, array, or mapping (got {property.ValueKind}).")
            };
    }

    static string CreateTerminalContinuingStringArrayExpression(JsonElement objectElement, string propertyName)
    {
        return objectElement.ValueKind != JsonValueKind.Object
            ? throw new InvalidOperationException($"Property '{propertyName}' must be a mapping.")
            : "new string[] { " +
               QuoteLiteral(GetRequiredString(objectElement, "terminal")) + ", " +
               QuoteLiteral(GetRequiredString(objectElement, "continuing")) +
               " }";
    }

    static string CreateConjoinedGenderedScaleArrayExpression(JsonElement arrayElement)
        => CreateTypedConstructorArrayExpression(
            "ConjoinedGenderedScale",
            arrayElement,
            RequiredInt64Value("divisor"),
            RequiredEnumValue("gender", "GrammaticalGender"),
            RequiredStringValue("singular"),
            RequiredStringValue("plural"),
            RequiredStringValue("ordinalStem"));

    static string CreateSegmentedScaleArrayExpression(JsonElement arrayElement)
        => CreateTypedConstructorArrayExpression(

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. If you intend a terminal/continuing pair, make the ordinal value a mapping with exactly 'terminal' and 'continuing' string keys.
  2. If you intend a list of forms, keep the value as a YAML sequence so the generator uses the array branch instead of the object branch.
  3. Rebuild after correcting the shape to confirm the generator accepts it.

Example fix

# before
ordinalSingular:
  - 'pierwszy'
# after
ordinalSingular:
  terminal: 'pierwszy'
  continuing: 'pierwszego'
Defensive patterns

Strategy: validation

Validate before calling

// When using the mapping form for an ordinal pair, assert the node is a
// mapping with exactly 'terminal' and 'continuing' scalar keys.

Prevention

When it happens

Trigger: A locale YAML defines ordinalSingular or ordinalPlural as a nested non-mapping (e.g. a sequence) that the generator routed to the object branch, or the value is a scalar inside a mapping context. The ValueKind check rejects anything that is not JsonValueKind.Object.

Common situations: Mixing the two mapping forms for ordinal pairs: providing a sequence where a mapping with 'terminal'/'continuing' was expected, or nesting scalars incorrectly. This is a build-time generator failure localized to the offending ordinal pair.

Related errors


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