{"record":{"id":"fd10baefe81f2bdc","repo":"Humanizr/Humanizer","slug":"array-backed-metric-scale-word-contracts-require-a","errorCode":null,"errorMessage":"Array-backed metric scale word contracts require a value property.","messagePattern":"Array-backed metric scale word contracts require a value property\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/NumberToWordsEngineContractFactory.cs","lineNumber":108,"sourceCode":"                AddContractMetricScaleWords(scaleWordContract, root, builderRoot, words);\n            }\n        }\n\n        static void AddContractMetricScaleWords(\n            MetricScaleWordContract contract,\n            JsonElement profileRoot,\n            JsonElement root,\n            Dictionary<char, MetricScaleWordDefinition> words)\n        {\n            if (contract.FixedValue is { } fixedValue)\n            {\n                AddContractMetricScaleWord(contract, fixedValue, profileRoot, root, words);\n                return;\n            }\n\n            if (contract.ValueProperty is null)\n            {\n                throw new InvalidOperationException(\"Array-backed metric scale word contracts require a value property.\");\n            }\n\n            foreach (var row in root.EnumerateArray())\n            {\n                AddContractMetricScaleWord(\n                    contract,\n                    GetRequiredInt64(row, contract.ValueProperty),\n                    profileRoot,\n                    row,\n                    words);\n            }\n        }\n\n        static void AddContractMetricScaleWord(\n            MetricScaleWordContract contract,\n            long value,\n            JsonElement profileRoot,\n            JsonElement row,","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/NumberToWordsEngineContractFactory.cs#L90-L126","documentation":"When collecting metric scale words from an array-backed contract, the factory needs to know which property in each array row holds the numeric scale value. If the MetricScaleWordContract has no FixedValue (which would bypass the array) and no ValueProperty (which names the value column), the code cannot enumerate rows and throws.","triggerScenarios":"A MetricScaleWordContract is constructed with both fixedValue=null and valueProperty=null, then AddContractMetricScaleWords is called. The contract reaches line 106 where ValueProperty is null and throws. This is typically a bug in the engine contract definition code, not in locale YAML.","commonSituations":"Defining a new engine contract in EngineContractCatalog that includes a metric-scale-words member without specifying either a fixed value or a value property. Refactoring contract definitions and dropping the valueProperty parameter. A contract was designed for FixedValue but the caller passes array data.","solutions":["In the engine contract definition (C# code, not YAML), set the valueProperty parameter on the MetricScaleWordContract to the YAML property name holding the numeric value.","Alternatively, set fixedValue to a specific metric value if the contract describes a single known scale word rather than an array.","Audit the MetricScaleWordContract constructor call to ensure at least one of valueProperty or fixedValue is non-null."],"exampleFix":"// before (in EngineContractCatalog C# code)\nnew MetricScaleWordContract(\n    valueProperty: null,\n    singularProperty: \"singular\",\n    pluralProperty: \"plural\")\n// after\nnew MetricScaleWordContract(\n    valueProperty: \"value\",\n    singularProperty: \"singular\",\n    pluralProperty: \"plural\")","handlingStrategy":"validation","validationCode":"// In the engine contract definition code, assert the contract is well-formed at startup:\nif (contract.FixedValue is null && contract.ValueProperty is null)\n    throw new ArgumentException(\"MetricScaleWordContract must define either FixedValue or ValueProperty.\");","typeGuard":"// Type guard for MetricScaleWordContract completeness\nstatic bool IsMetricScaleWordContractValid(MetricScaleWordContract c) =>\n    c.FixedValue is not null || !string.IsNullOrEmpty(c.ValueProperty);","tryCatchPattern":null,"preventionTips":["When defining a new MetricScaleWordContract, always provide either valueProperty or fixedValue.","Add a unit test that validates every contract in EngineContractCatalog has a non-null ValueProperty or FixedValue.","Use constructor validation to reject null-for-both at definition time rather than at generation time."],"tags":["metric-scale-words","source-generator","number-to-words","contract","build-time"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}