devlooped/moq · error · ArgumentOutOfRangeException

ArgumentOutOfRangeException: callCountTo (invalid range…

Error message

ArgumentOutOfRangeException: callCountTo (invalid range bounds for Times.Between with Range.Exclusive)

What it means

For Times.Between with Range.Exclusive, when from and to differ by exactly 1 there is no integer strictly between them, so the call throws ArgumentOutOfRangeException named callCountTo. This is the 'empty exclusive range' check that complements the callCountFrom bounds check.

Solutions

  1. Use Range.Inclusive for adjacent bounds: Times.Between(2, 3, Range.Inclusive)
  2. Widen the exclusive bounds by one (Between(1, 4, Exclusive)) if exclusivity is truly required
  3. Validate to - from > 1 before calling with Range.Exclusive

Example fix

// before
mock.Verify(m => m.Foo(), Times.Between(2, 3, Range.Exclusive));
// after
mock.Verify(m => m.Foo(), Times.Between(2, 3, Range.Inclusive));
Defensive patterns

Strategy: validation

Validate before calling

if (to - from > 1)
    mock.Verify(m => m.Foo(), Times.Between(from, to, Range.Exclusive));
else
    mock.Verify(m => m.Foo(), Times.Between(from, to, Range.Inclusive));

Prevention

When it happens

Trigger: Times.Between(2, 3, Range.Exclusive), Times.Between(5, 6, Range.Exclusive) — any exclusive interval with to - from == 1 (after the from/to ordering checks pass).

Common situations: Translating inclusive requirements ('at least 2, at most 3') into Exclusive range by mistake; dynamic bounds that happen to be adjacent.

Related errors


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

Appendix: source

Thrown at src/Moq/Times.cs:124

        ///   Specifies that a mocked method should be invoked between
        ///   <paramref name="callCountFrom"/> and <paramref name="callCountTo"/> times.
        /// </summary>
        /// <param name="callCountFrom">The minimum number of times.</param>
        /// <param name="callCountTo">The maximum number of times.</param>
        /// <param name="rangeKind">The kind of range. See <see cref="Range"/>.</param>
        /// <returns>An object defining the allowed number of invocations.</returns>
        public static Times Between(int callCountFrom, int callCountTo, Range rangeKind)
        {
            if (rangeKind == Range.Exclusive)
            {
                if (callCountFrom <= 0 || callCountTo <= callCountFrom)
                {
                    throw new ArgumentOutOfRangeException(nameof(callCountFrom));
                }

                if (callCountTo - callCountFrom == 1)
                {
                    throw new ArgumentOutOfRangeException(nameof(callCountTo));
                }

                return new Times(Kind.BetweenExclusive, callCountFrom + 1, callCountTo - 1);
            }

            if (callCountFrom < 0 || callCountTo < callCountFrom)
            {
                throw new ArgumentOutOfRangeException(nameof(callCountFrom));
            }

            return new Times(Kind.BetweenInclusive, callCountFrom, callCountTo);
        }

        /// <summary>
        ///   Specifies that a mocked method should be invoked exactly
        ///   <paramref name="callCount"/> times.
        /// </summary>
        /// <param name="callCount">The times that a method or property can be called.</param>

View on GitHub (pinned to 89a5be629c)