{"record":{"id":"8aadfbe3d30f49b1","repo":"FluentValidation/FluentValidation","slug":"scale-must-be-a-positive-integer-value-scale","errorCode":null,"errorMessage":"Scale must be a positive integer. [value:{Scale}].","messagePattern":"Scale must be a positive integer\\. \\[value:(.+?)\\]\\.","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/FluentValidation/Validators/PrecisionScaleValidator.cs","lineNumber":50,"sourceCode":"///\r\n/// It implies certain range of values that will be accepted by the validator.\r\n/// It permits up to Precision - Scale digits to the left of the decimal point and up to Scale digits to the right.\r\n///\r\n/// It can be configured to use the effective scale and precision\r\n/// (i.e. ignore trailing zeros) if required.\r\n///\r\n/// 123.4500 has an scale of 4 and a precision of 7, but an effective scale\r\n/// and precision of 2 and 5 respectively.\r\n/// </summary>\r\npublic class PrecisionScaleValidator<T> : PropertyValidator<T, decimal> {\r\n\r\n\tpublic PrecisionScaleValidator(int precision, int scale, bool ignoreTrailingZeros) {\r\n\t\tScale = scale;\r\n\t\tPrecision = precision;\r\n\t\tIgnoreTrailingZeros = ignoreTrailingZeros;\r\n\r\n\t\tif (Scale < 0)\r\n\t\t\tthrow new ArgumentOutOfRangeException(nameof(scale), $\"Scale must be a positive integer. [value:{Scale}].\");\r\n\r\n\t\tif (Precision < 0)\r\n\t\t\tthrow new ArgumentOutOfRangeException(nameof(precision), $\"Precision must be a positive integer. [value:{Precision}].\");\r\n\r\n\t\tif (Precision < Scale)\r\n\t\t\tthrow new ArgumentOutOfRangeException(nameof(scale), $\"Scale must be less than precision. [scale:{Scale}, precision:{Precision}].\");\r\n\t}\r\n\r\n\tpublic override string Name => \"ScalePrecisionValidator\";\r\n\r\n\tpublic int Scale { get; }\r\n\r\n\tpublic int Precision { get; }\r\n\r\n\tpublic bool IgnoreTrailingZeros { get; }\r\n\r\n\tpublic override bool IsValid(ValidationContext<T> context, decimal decimalValue) {\r\n\t\tvar info = Info.Get(decimalValue, IgnoreTrailingZeros);\r","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/FluentValidation/FluentValidation/blob/daa00b795450881c233253488e3ddeb362f59f56/src/FluentValidation/Validators/PrecisionScaleValidator.cs#L32-L68","documentation":"Constructor precondition of PrecisionScaleValidator: the scale (number of digits after the decimal point) must not be negative. Thrown immediately when PrecisionScale(precision, scale, ignoreTrailingZeros) is called with a negative scale. Note the message says 'positive integer' but the guard only rejects values below zero, so 0 is accepted.","triggerScenarios":"Calling RuleFor(x => x.Amount).PrecisionScale(precision, scale, ignoreTrailingZeros) with scale < 0, or direct construction new PrecisionScaleValidator<T>(5, -1, false).","commonSituations":"Negative scale passed due to a config typo or a computed value that underflows. Misunderstanding scale vs precision and passing the wrong argument. Argument-order confusion (precision comes first).","solutions":["Pass a non-negative scale as the second argument, e.g. .PrecisionScale(5, 2, false) for up to 5 total digits with 2 after the decimal.","Remember argument order is (precision, scale, ignoreTrailingZeros) — scale is second.","If scale comes from config, validate/clamp it to >= 0 before building the rule."],"exampleFix":"// before\nRuleFor(x => x.Amount).PrecisionScale(5, -2, false);\n\n// after\nRuleFor(x => x.Amount).PrecisionScale(5, 2, false);","handlingStrategy":"validation","validationCode":"int scale = 2;\nif (scale < 0) throw new ArgumentOutOfRangeException(nameof(scale));\nRuleFor(x => x.Amount).PrecisionScale(5, scale, false);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember PrecisionScale argument order: (precision, scale, ignoreTrailingZeros).","Clamp config-driven scale/precision to non-negative values before use.","Unit-test the rule construction with the smallest/largest configured values."],"tags":["precision","configuration","fluentvalidation"],"backgroundTag":null,"analyzedSha":"daa00b795450881c233253488e3ddeb362f59f56","analyzedAt":"2026-08-13T20:45:43.800Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}