{"record":{"id":"432cf8c04b9451cc","repo":"Humanizr/Humanizer","slug":"locale-document-localecode-surfaces-surface-ke","errorCode":null,"errorMessage":"Locale '{document.LocaleCode}.surfaces.{surface.Key}' must be a mapping.","messagePattern":"Locale '(.+?)\\.surfaces\\.(.+?)' must be a mapping\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs","lineNumber":143,"sourceCode":"\n            return new CanonicalLocaleDocument(\n                localeCode,\n                variantOf,\n                surfaces,\n                NormalizeCanonicalText(fileText));\n        }\n\n        internal static string Emit(CanonicalLocaleDocument document) => document.CanonicalText;\n\n        internal static LocaleDefinition ToLocaleDefinition(CanonicalLocaleDocument document)\n        {\n            var features = ImmutableDictionary.CreateBuilder<string, SimpleYamlValue>(StringComparer.Ordinal);\n\n            foreach (var surface in document.Surfaces.Values)\n            {\n                if (surface.Value is not SimpleYamlMapping surfaceMapping)\n                {\n                    throw new InvalidOperationException(\n                        $\"Locale '{document.LocaleCode}.surfaces.{surface.Key}' must be a mapping.\");\n                }\n\n                switch (surface.Key)\n                {\n                    case \"list\":\n                        features[\"collectionFormatter\"] = NormalizeListSurface(document.LocaleCode, surfaceMapping);\n                        break;\n\n                    case \"formatter\":\n                        features[\"formatter\"] = surfaceMapping;\n                        var grammar = ImmutableDictionary.CreateBuilder<string, SimpleYamlValue>(StringComparer.Ordinal);\n                        foreach (var propertyName in FormatterGrammarPropertyNames.Where(surfaceMapping.Values.ContainsKey))\n                        {\n                            grammar[propertyName] = surfaceMapping.Values[propertyName];\n                        }\n\n                        if (grammar.Count > 0)","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs#L125-L161","documentation":"ToLocaleDefinition re-checks that each surface value is a mapping before dispatching on its name (CanonicalLocaleAuthoring.cs:139-145). The Parse path already enforces this, so reaching this throw means a CanonicalLocaleDocument was constructed or mutated outside Parse (e.g. legacy migration, a test fixture, or code that built the document by hand).","triggerScenarios":"A code path builds a CanonicalLocaleDocument directly with a non-mapping surface value and passes it to ToLocaleDefinition; or the migration helper emits a malformed surface.","commonSituations":"Writing a unit test that constructs CanonicalLocaleDocument manually; extending the migration tooling and producing a sequence/scalar surface.","solutions":["Always obtain documents via CanonicalLocaleAuthoring.Parse so the surface-shape invariant holds.","If constructing programmatically, ensure every value in the surfaces mapping is a SimpleYamlMapping.","Reproduce via Parse to surface the earlier, more specific error and fix it there."],"exampleFix":"// before (test/migration builds a document with a scalar surface)\nvar doc = new CanonicalLocaleDocument(\"en\", null, surfacesWithScalarClock, text);\nToLocaleDefinition(doc); // throws\n// after\nvar doc = CanonicalLocaleAuthoring.Parse(\"en\", canonicalYaml); // surfaces.clock is a mapping","handlingStrategy":"type-guard","validationCode":"// Before calling ToLocaleDefinition, ensure every surface is a mapping\nstatic bool AllSurfacesAreMappings(CanonicalLocaleDocument d)\n    => d.Surfaces.Values.All(kv => kv.Value is SimpleYamlMapping);","typeGuard":"static bool IsValidLocaleDocument(CanonicalLocaleDocument d) =>\n    d.Surfaces.Values.All(kv => kv.Value is SimpleYamlMapping);","tryCatchPattern":null,"preventionTips":["Treat Parse as the only constructor of CanonicalLocaleDocument.","If you must build one by hand, assert all surfaces are SimpleYamlMapping first.","Prefer fixing the input YAML over special-casing the conversion path."],"tags":["locale-authoring","yaml","source-generator","build","localization","internal-api"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}