devlooped/moq · error · ArgumentException

Minimum delay has to be lower than maximum delay.

Error message

Minimum delay has to be lower than maximum delay.

What it means

GetDelay requires minDelay to be strictly less than maxDelay; when minDelay >= maxDelay it throws ArgumentException('Minimum delay has to be lower than maximum delay.') because random.Next(min, max) would be undefined/empty for that range.

Solutions

  1. Ensure maxDelay is strictly greater than minDelay, e.g. (0s, 1s) instead of (1s, 1s)
  2. For a fixed delay use the ReturnsAsync/ThrowsAsync (value, TimeSpan delay) overloads instead of min/max
  3. Validate inputs before the call: if (minDelay < maxDelay) { ... }

Example fix

// before
mock.Setup(m => m.GetAsync()).ReturnsAsync(v, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), random);
// after
mock.Setup(m => m.GetAsync()).ReturnsAsync(v, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), random);
Defensive patterns

Strategy: validation

Validate before calling

if (minDelay >= maxDelay) throw new ArgumentException("minDelay must be strictly less than maxDelay");

Type guard

bool IsValidDelayRange(TimeSpan min, TimeSpan max) => min < max;

Try / catch

try { mock.Setup(m => m.GetAsync()).ReturnsAsync(v, min, max, random); } catch (ArgumentException ex) when (ex.Message.Contains("Minimum delay")) { /* fix the range or use fixed delay */ }

Prevention

When it happens

Trigger: Calling ReturnsAsync/ThrowsAsync with minDelay == maxDelay (e.g. TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)) or minDelay > maxDelay (swapped arguments).

Common situations: Passing equal timespans to get a 'fixed' delay; accidentally swapping min and max parameters; computing delays from constants that happen to be equal.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16). Data as JSON: /api/errors/aa680195f545c8b5. Report an issue: GitHub.

Appendix: source

Thrown at src/Moq/ReturnsExtensions.cs:306

        internal static bool IsNullResult([NotNullWhen(false)] Delegate? valueFunction, Type resultType)
#else
        internal static bool IsNullResult(Delegate? valueFunction, Type resultType)
#endif
        {
            if (valueFunction == null)
            {
                return !resultType.IsValueType || Nullable.GetUnderlyingType(resultType) != null;
            }
            else
            {
                return false;
            }
        }

        static TimeSpan GetDelay(TimeSpan minDelay, TimeSpan maxDelay, Random random)
        {
            if (minDelay >= maxDelay)
                throw new ArgumentException(Resources.MinDelayMustBeLessThanMaxDelay);

            var min = (int)minDelay.Ticks;
            var max = (int)maxDelay.Ticks;

            return new TimeSpan(random.Next(min, max));
        }

        static IReturnsResult<TMock> DelayedResult<TMock, TResult>(IReturns<TMock, Task<TResult>> mock,
            TResult value, TimeSpan delay)
            where TMock : class
        {
            Guard.Positive(delay);

            return mock.Returns(() =>
            {
                return Task.Delay(delay).ContinueWith(t => value);
            });
        }

View on GitHub (pinned to 89a5be629c)