louthy/language-ext · error · ArgumentException

milliseconds must be a positive number.

Error message

milliseconds must be a positive number.

What it means

The Duration(double milliseconds) constructor validates that the magnitude is non-negative and throws ArgumentException with the message "milliseconds must be a positive number." if the value is below 0. LanguageExt schedules cannot represent negative (past) durations.

Solutions

  1. Clamp the computed value: Math.Max(0, milliseconds) before constructing Duration.
  2. Fix the calculation producing the negative interval (ordering of timestamps).
  3. Validate config/inputs so negative delays are rejected or coerced earlier.

Example fix

// before
var d = new Duration(next - prev);
// after
var d = new Duration(Math.Max(0, next - prev));
Defensive patterns

Strategy: validation

Validate before calling

if (milliseconds < 0) throw new ArgumentOutOfRangeException(nameof(milliseconds));
var d = new Duration(Math.Max(0, milliseconds));

Type guard

static bool IsValidDuration(double ms) => !double.IsNaN(ms) && ms >= 0;

Try / catch

try { var d = new Duration(ms); } catch (ArgumentException e) { /* negative duration */ }

Prevention

When it happens

Trigger: new Duration(-1), passing a negative computed interval (e.g. endTime - startTime where start > end), or subtracting delays that underflow into negative values when building a Schedule.

Common situations: Computing retry backoff from timestamps where clocks are out of order, parsing config values that may be negative, or subtracting elapsed from remaining time that has already gone negative.

Related errors


AI-assisted analysis of louthy/language-ext@2f0e362824 (2026-09-15). Data as JSON: /api/errors/8548f1b9a9d6b8f9. Report an issue: GitHub.

Appendix: source

Thrown at LanguageExt.Core/Effects/Schedule/Duration.cs:24

/// <summary>
/// Period of time in milliseconds.
/// Can be used to convert between other duration like types, such as TimeSpan and Time.
/// </summary>
public readonly struct Duration :
    IEquatable<Duration>,
    IComparable<Duration>
{
    public readonly double Milliseconds;

    /// <summary>
    /// Duration constructor
    /// </summary>
    /// <param name="milliseconds">Magnitude of the duration.  Must be zero or a positive value</param>
    /// <exception cref="ArgumentException">Throws if `milliseconds` is less than `0`</exception>
    public Duration(double milliseconds)
    {
        if (milliseconds < 0) throw new ArgumentException($"{nameof(milliseconds)} must be a positive number.");
        Milliseconds = milliseconds;
    }

    /// <summary>
    /// Zero magnitude duration (instant)
    /// </summary>
    public static Duration Zero =
        new(0);
    
    /// <summary>
    /// Return true if the time duration is zero
    /// </summary>
    public bool IsZero =>
        Milliseconds < 0.00000000001;

    /// <summary>
    /// Random duration between the provided min and max durations. 
    /// </summary>

View on GitHub (pinned to 2f0e362824)