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 'maxDenominator')

What it means

Thrown by Fractionalize when maxDenominator is less than 1. On .NET 8+ it uses ArgumentOutOfRangeException.ThrowIfLessThan(maxDenominator, 1); on older targets it throws manually. A denominator of 1 (whole numbers only) is allowed. The parameter is named 'maxDenominator'.

Source

Thrown at src/Humanizer/FractionalizeExtensions.cs:47

    /// <example>
    /// <code>
    /// 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);
    }

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Clamp maxDenominator to at least 1 before calling: Math.Max(1, requestedDenominator).
  2. Validate the source configuration/int input at the boundary and reject values below 1 with a clear error.
  3. Choose a sensible application default (e.g. 64 or 100) and only override with validated input.

Example fix

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

// after
var denom = Math.Max(1, maxDenominatorFromConfig);
var f = value.Fractionalize(denom, tolerance);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

static bool IsValidMaxDenominator(int d) => d >= 1;

Try / catch

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

Prevention

When it happens

Trigger: Calling value.Fractionalize(0, 0m) or value.Fractionalize(-5, 0.01m); passing a maxDenominator derived from user input or configuration without a lower bound; computing the denominator from a precision setting that can evaluate to zero or negative.

Common situations: Exposing maxDenominator as a user-tunable precision knob with no min validation; defaulting the argument from an optional config value that is missing and falls back to 0; arithmetic that subtracts a safety margin and underflows.

Related errors


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