{"record":{"id":"a1e473bbc6868352","repo":"Humanizr/Humanizer","slug":"locale-localecode-featurename-must-declare-a","errorCode":null,"errorMessage":"Locale '{localeCode}.{featureName}' must declare an 'engine'.","messagePattern":"Locale '(.+?)\\.(.+?)' must declare an 'engine'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/LocaleYamlCatalog.cs","lineNumber":966,"sourceCode":"                var localEngine = localMapping.GetScalar(\"engine\");\n                return inheritedEngine is not null &&\n                    localEngine is not null &&\n                    !string.Equals(inheritedEngine, localEngine, StringComparison.Ordinal)\n                    ? localMapping\n                    : MergeMappings(path, inheritedMapping, localMapping);\n            }\n\n            // Ordered lexical data such as scale lists and token tables stay explicit.\n            // A child sequence replaces the parent sequence rather than trying to merge by index.\n            return localValue;\n        }\n\n        static LocaleFeature CreateMappedFeature(string localeCode, string featureName, SimpleYamlMapping mapping)\n        {\n            if (featureName == \"collectionFormatter\")\n            {\n                var engine = mapping.GetScalar(\"engine\")\n                    ?? throw new InvalidOperationException($\"Locale '{localeCode}.{featureName}' must declare an 'engine'.\");\n                return new LocaleFeature(localeCode, featureName, engine, mapping.GetScalar(\"value\"), null, default, false);\n            }\n\n            if (featureName == \"wordsToNumber\" &&\n                string.Equals(mapping.GetScalar(\"engine\"), \"token-map\", StringComparison.Ordinal))\n            {\n                return new LocaleFeature(localeCode, featureName, \"lexicon\", localeCode, null, ToJsonElement(NormalizeFeatureReferences(localeCode, featureName, mapping)), false);\n            }\n\n            if (featureName is \"dateToOrdinalWords\" or \"dateOnlyToOrdinalWords\" &&\n                string.Equals(mapping.GetScalar(\"engine\"), \"default\", StringComparison.Ordinal) &&\n                mapping.GetScalar(\"pattern\") is not null)\n            {\n                var values = mapping.Values.SetItem(\"engine\", new SimpleYamlScalar(\"pattern\", isQuoted: true));\n                mapping = new SimpleYamlMapping(values);\n            }\n\n            if (featureName is \"formatter\" or \"ordinalizer\" or \"dateToOrdinalWords\" or \"dateOnlyToOrdinalWords\" or \"timeOnlyToClockNotation\")","sourceCodeStart":948,"sourceCodeEnd":984,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/LocaleYamlCatalog.cs#L948-L984","documentation":"The 'collectionFormatter' feature, when provided as a mapping, must declare an 'engine' key so the generator knows which collection-formatting strategy to wire up. Without it the feature is ambiguous and the generator cannot select an implementation.","triggerScenarios":"A locale's 'collectionFormatter:' mapping contains a 'value:' key (or other keys) but omits the required 'engine:' key.","commonSituations":"Authoring collection formatting for the first time and forgetting the engine selector; partially copying a mapping and dropping the engine line; indentation causing 'engine:' to attach elsewhere.","solutions":["Add an 'engine:' key to the collectionFormatter mapping (e.g. 'engine: default' or 'engine: oxford').","Verify the engine value matches a supported collection formatter engine name.","If a scalar shorthand is sufficient, replace the mapping with 'collectionFormatter: default'."],"exampleFix":"# before\ncollectionFormatter:\n  value: oxford\n\n# after\ncollectionFormatter:\n  engine: oxford\n  value: \"\"","handlingStrategy":"validation","validationCode":"import yaml, pathlib\nlocales_dir = pathlib.Path('src/Humanizer/Locales')\nfor f in locales_dir.rglob('*.yml'):\n    data = yaml.safe_load(f.read_text())\n    if isinstance(data, dict) and isinstance(data.get('collectionFormatter'), dict):\n        if 'engine' not in data['collectionFormatter']:\n            print(f'{f.name}: collectionFormatter mapping must declare \"engine\"')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include an 'engine:' key inside a collectionFormatter mapping.","If only a default engine is needed, use the scalar shorthand 'collectionFormatter: default'.","Check the engine value against supported collection formatter engine names."],"tags":["locale","yaml","source-generator","collection-formatter","required-field"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}