FluentValidation/FluentValidation · error · ArgumentOutOfRangeException
Scale must be a positive integer. [value:{Scale}].
Error message
Scale must be a positive integer. [value:{Scale}]. What it means
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.
Source
Thrown at src/FluentValidation/Validators/PrecisionScaleValidator.cs:50
///
/// It implies certain range of values that will be accepted by the validator.
/// It permits up to Precision - Scale digits to the left of the decimal point and up to Scale digits to the right.
///
/// It can be configured to use the effective scale and precision
/// (i.e. ignore trailing zeros) if required.
///
/// 123.4500 has an scale of 4 and a precision of 7, but an effective scale
/// and precision of 2 and 5 respectively.
/// </summary>
public class PrecisionScaleValidator<T> : PropertyValidator<T, decimal> {
public PrecisionScaleValidator(int precision, int scale, bool ignoreTrailingZeros) {
Scale = scale;
Precision = precision;
IgnoreTrailingZeros = ignoreTrailingZeros;
if (Scale < 0)
throw new ArgumentOutOfRangeException(nameof(scale), $"Scale must be a positive integer. [value:{Scale}].");
if (Precision < 0)
throw new ArgumentOutOfRangeException(nameof(precision), $"Precision must be a positive integer. [value:{Precision}].");
if (Precision < Scale)
throw new ArgumentOutOfRangeException(nameof(scale), $"Scale must be less than precision. [scale:{Scale}, precision:{Precision}].");
}
public override string Name => "ScalePrecisionValidator";
public int Scale { get; }
public int Precision { get; }
public bool IgnoreTrailingZeros { get; }
public override bool IsValid(ValidationContext<T> context, decimal decimalValue) {
var info = Info.Get(decimalValue, IgnoreTrailingZeros);
View on GitHub (pinned to daa00b7954)
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.
Example fix
// before RuleFor(x => x.Amount).PrecisionScale(5, -2, false); // after RuleFor(x => x.Amount).PrecisionScale(5, 2, false);
Defensive patterns
Strategy: validation
Validate before calling
int scale = 2; if (scale < 0) throw new ArgumentOutOfRangeException(nameof(scale)); RuleFor(x => x.Amount).PrecisionScale(5, scale, false);
Prevention
- 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.
When it happens
Trigger: Calling RuleFor(x => x.Amount).PrecisionScale(precision, scale, ignoreTrailingZeros) with scale < 0, or direct construction new PrecisionScaleValidator<T>(5, -1, false).
Common situations: 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).
Related errors
- Precision must be a positive integer. [value:{Precision}].
- Scale must be less than precision. [scale:{Scale}, precision
- Max should be larger than min.
- Validator {validator.GetType().Name} can't validate instance
- To should be larger than from.
AI-assisted analysis of FluentValidation/FluentValidation@daa00b7954 (2026-08-13).
Data as JSON: /api/errors/8aadfbe3d30f49b1.
Report an issue: GitHub.