Humanizr/Humanizer · error · ArgumentOutOfRangeException

Specified argument was out of the range of valid values. (Pa

Error message

Specified argument was out of the range of valid values. (Parameter 'tolerance')

What it means

Thrown by Fractionalize when tolerance is negative. Tolerance represents the maximum absolute difference allowed between the input and its fractional approximation, so a negative value is meaningless; zero is allowed (exact match required). On .NET 8+ it uses ArgumentOutOfRangeException.ThrowIfNegative; otherwise a manual throw. The parameter is named 'tolerance'.

Source

Thrown at src/Humanizer/FractionalizeExtensions.cs:49

    /// 1.25m.Fractionalize(5, 0m) => "1 1/4"
    /// 0.34m.Fractionalize(5, 0.01m) => "1/3"
    /// 0.75m.Fractionalize(4, 0m, useUnicode: true) => "¾"
    /// </code>
    /// </example>
    public static string Fractionalize(
        this decimal input,
        int maxDenominator,
        decimal tolerance,
        bool useUnicode = false)
    {
#if NET8_0_OR_GREATER
        ArgumentOutOfRangeException.ThrowIfLessThan(maxDenominator, 1);
        ArgumentOutOfRangeException.ThrowIfNegative(tolerance);
#else
        if (maxDenominator < 1)
            throw new ArgumentOutOfRangeException(nameof(maxDenominator));
        if (tolerance < 0)
            throw new ArgumentOutOfRangeException(nameof(tolerance));
#endif

        if (decimal.Truncate(input) == input)
            return input.ToString("0", CultureInfo.InvariantCulture);

        var value = ToFraction(input);
        var approximation = LimitDenominator(BigInteger.Abs(value.Numerator), value.Denominator, maxDenominator);
        if (value.Numerator.Sign < 0)
            approximation.Numerator = -approximation.Numerator;

        if (!IsWithinTolerance(value, approximation, ToFraction(tolerance)))
            return input.ToString(LocaleNumberFormattingOverrides.GetFormattingNumberFormat(CultureInfo.CurrentCulture));

        return Format(approximation, useUnicode);
    }

    static (BigInteger Numerator, BigInteger Denominator) ToFraction(decimal value)
    {

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Use Math.Abs(tolerance) or default to 0m when the computed tolerance is negative.
  2. Validate tolerance at the configuration boundary and reject negative values with a descriptive error.
  3. When you want an exact fraction, pass 0m explicitly rather than relying on a computed near-zero value.

Example fix

// before
var f = value.Fractionalize(64, tolerance);

// after
var tol = tolerance < 0 ? 0m : tolerance;
var f = value.Fractionalize(64, tol);
Defensive patterns

Strategy: validation

Validate before calling

if (tolerance < 0)
    throw new ArgumentOutOfRangeException(nameof(tolerance), "Must be >= 0.");
var f = input.Fractionalize(maxDenominator, tolerance);

Type guard

static bool IsValidTolerance(decimal t) => t >= 0;

Try / catch

try { return input.Fractionalize(maxDenominator, tolerance); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "tolerance")
{ return input.Fractionalize(maxDenominator, 0m); }

Prevention

When it happens

Trigger: Calling value.Fractionalize(64, -0.01m); passing a tolerance computed as a difference that can go negative; deserializing tolerance from config where a sign error or missing value yields a negative decimal.

Common situations: Tolerance derived from a percentage/epsilon that underflows to a small negative due to floating/decimal arithmetic; configuration stored as a magnitude with a sign flag that is misread; reusing an 'allowed error' field for another purpose.

Related errors


AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13). Data as JSON: /api/errors/cb4bf97fb1726e16. Report an issue: GitHub.