{"record":{"id":"e7bedddba9bdb927","repo":"Humanizr/Humanizer","slug":"locale-localecode-defines-unsupported-top-leve","errorCode":null,"errorMessage":"Locale '{localeCode}' defines unsupported top-level property '{property}'. Supported properties: {string.Join(\", \", SupportedTopLevelNames)}.","messagePattern":"Locale '(.+?)' defines unsupported top-level property '(.+?)'\\. Supported properties: (.+?)\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs","lineNumber":72,"sourceCode":"\n        static readonly string[] FormatterGrammarPropertyNames =\n        [\n            \"pluralRule\",\n            \"casePluralRule\",\n            \"dataUnitPluralRule\",\n            \"dataUnitNonIntegralForm\",\n            \"prepositionMode\",\n            \"secondaryPlaceholderMode\",\n            \"timeUnitGenders\"\n        ];\n\n        internal static CanonicalLocaleDocument Parse(string localeCode, string fileText)\n        {\n            var root = SimpleYamlParser.Parse(fileText);\n\n            foreach (var property in root.Values.Keys.Where(static property => !SupportedTopLevelNames.Contains(property, StringComparer.Ordinal)))\n            {\n                throw new InvalidOperationException(\n                    $\"Locale '{localeCode}' defines unsupported top-level property '{property}'. \" +\n                    $\"Supported properties: {string.Join(\", \", SupportedTopLevelNames)}.\");\n            }\n\n            var declaredLocale = root.GetScalar(\"locale\")\n                ?? throw new InvalidOperationException(\n                    $\"Locale '{localeCode}' must define required top-level property 'locale'.\");\n\n            if (!string.Equals(localeCode, declaredLocale, StringComparison.Ordinal))\n            {\n                throw new InvalidOperationException(\n                    $\"Locale '{declaredLocale}' must match file locale '{localeCode}'.\");\n            }\n\n            var variantOf = root.GetScalar(\"variantOf\");\n\n            SimpleYamlMapping surfaces;\n            if (!root.TryGetValue(\"surfaces\", out var surfacesValue))","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs#L54-L90","documentation":"During the source-generator build, CanonicalLocaleAuthoring.Parse rejects any top-level YAML key not in {locale, variantOf, surfaces} (CanonicalLocaleAuthoring.cs:70-75). The canonical schema is intentionally tiny; legacy flat keys (inherits, collectionFormatter, etc.) are rejected here and must be migrated first.","triggerScenarios":"A locale YAML file under src/Humanizer/Locales contains a key outside locale/variantOf/surfaces — e.g. a typo (surface:), a leftover legacy key (inherits:, formatter: at top level), or a copied block pasted at the wrong indentation.","commonSituations":"Copying an old pre-canonical locale file; typoing 'surfaces' as 'surface'; merging a PR that uses a renamed property.","solutions":["Read the message: it names the offending property and lists allowed names.","If the property is legacy (inherits, formatter, numberToWords...), run LegacyLocaleMigration.ConvertToCanonicalYaml to migrate it, or move it under the correct surface.","Fix typos: surface -> surfaces.","Remove any genuinely unwanted top-level key."],"exampleFix":"# before\nlocale: \"fr\"\ninherit: \"en\"\nsurfaces:\n  clock: {}\n# after\nlocale: \"fr\"\nvariantOf: \"en\"\nsurfaces:\n  clock: {}","handlingStrategy":"validation","validationCode":"# Quick YAML lint: allowed top-level keys only\nimport yaml, sys\nALLOWED = {'locale','variantOf','surfaces'}\ndoc = yaml.safe_load(open(sys.argv[1], encoding='utf-8'))\nbad = [k for k in doc if k not in ALLOWED]\nassert not bad, f'unsupported top-level keys: {bad}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Author locales against the canonical schema; the error message lists the exact allowed names.","Run `dotnet build src/Humanizer/Humanizer.csproj` locally so the generator reports locale errors before push.","Copy an existing compliant locale file as your template rather than writing YAML from scratch."],"tags":["locale-authoring","yaml","source-generator","build","localization","schema"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}