Humanizr/Humanizer · error · InvalidOperationException
Legacy locale '{localeCode}' defines unsupported top-level p
Error message
Legacy locale '{localeCode}' defines unsupported top-level property '{property}'. What it means
Thrown by LegacyLocaleMigration.ConvertToCanonicalYaml when a legacy locale file contains a top-level YAML property that is not in the LegacyTopLevelNames whitelist (inherits, collectionFormatter, dateOnlyToOrdinalWords, dateToOrdinalWords, durationCases, formatter, grammar, headings, numberToWords, ordinalizer, phrases, timeOnlyToClockNotation, wordsToNumber). The migration tool only knows how to translate these specific legacy properties into canonical surfaces.
Source
Thrown at src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs:658
"dateOnlyToOrdinalWords",
"dateToOrdinalWords",
"durationCases",
"formatter",
"grammar",
"headings",
"numberToWords",
"ordinalizer",
"phrases",
"timeOnlyToClockNotation",
"wordsToNumber"
];
public static string ConvertToCanonicalYaml(string localeCode, string fileText)
{
var root = SimpleYamlParser.Parse(fileText);
foreach (var property in root.Values.Keys.Where(static property => !LegacyTopLevelNames.Contains(property, StringComparer.Ordinal)))
{
throw new InvalidOperationException(
$"Legacy locale '{localeCode}' defines unsupported top-level property '{property}'.");
}
var builder = new StringBuilder();
builder.Append("locale: ");
builder.AppendLine(QuoteScalar(new SimpleYamlScalar(localeCode, true)));
if (root.GetScalar("inherits") is { } variantOf)
{
builder.Append("variantOf: ");
builder.AppendLine(QuoteScalar(new SimpleYamlScalar(variantOf, true)));
}
var hasInherits = root.GetScalar("inherits") is not null;
var hasSurfaces = root.Values.Keys.Any(static key => key != "inherits");
if (!hasSurfaces)
{
if (hasInherits)View on GitHub (pinned to ffc2b77c0f)
Solutions
- Remove or rename the unsupported top-level property so only whitelisted legacy names remain.
- If the property is already canonical (e.g. 'surfaces'), migrate the entire file to canonical format instead of using ConvertToCanonicalYaml.
- Check the LegacyTopLevelNames array in CanonicalLocaleAuthoring.cs:636 for the exact list of accepted property names.
Example fix
# before (legacy file with unsupported key) ordinal: engine: default inherits: en # after (remove non-legacy key; or convert fully to canonical) inherits: en
Defensive patterns
Strategy: validation
Validate before calling
static readonly HashSet<string> LegacyTopLevelNames = new(StringComparer.Ordinal)
{
"inherits", "collectionFormatter", "dateOnlyToOrdinalWords", "dateToOrdinalWords",
"durationCases", "formatter", "grammar", "headings", "numberToWords",
"ordinalizer", "phrases", "timeOnlyToClockNotation", "wordsToNumber"
};
static string? FindUnsupportedLegacyKey(SimpleYamlMapping root) =>
root.Values.Keys.FirstOrDefault(k => !LegacyTopLevelNames.Contains(k)); Try / catch
// Wrap ConvertToCanonicalYaml for safe migration with diagnostics
try
{
var canonical = LegacyLocaleMigration.ConvertToCanonicalYaml(localeCode, fileText);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("unsupported top-level property"))
{
logger.LogWarning("Locale {Locale} has unsupported legacy properties; skipping migration", localeCode);
throw;
} Prevention
- Only run ConvertToCanonicalYaml on genuinely legacy locale files, not partially-converted ones.
- Check every root-level key against the LegacyTopLevelNames list before migrating.
- Prefer authoring canonical YAML directly for new locales.
When it happens
Trigger: ConvertToCanonicalYaml parses the legacy file, iterates root.Values.Keys, and throws for any key not in LegacyTopLevelNames. For example, a legacy file with a top-level 'ordinal:' or 'clock:' key (which are canonical surface names, not legacy names) would fail.
Common situations: A contributor runs the legacy migration on a file that was already partially converted to canonical format, mixing canonical and legacy keys. Or a custom/typo property name is present at the root level. Also happens when a locale file uses an older schema with properties the migration tool doesn't recognize.
Related errors
- Locale '{localeCode}.{path}' must omit the block instead of
- Locale '{localeCode}.{path}' defines duplicate numeric minut
- Locale '{localeCode}.{path}.{key}' must be a string.
- Locale '{localeCode}.{path}.{key}' must be a non-empty strin
- Locale '{localeCode}.surfaces.number.formatting' defines uns
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/d50d530f53a474cd.
Report an issue: GitHub.