devlooped/moq · error · InvalidOperationException

InvalidOperationException (unhandled Times kind in ToString)

Error message

InvalidOperationException (unhandled Times kind in ToString)

What it means

Times.ToString() switches over the internal Kind enum and throws InvalidOperationException when no case matches. This is an internal invariant violation — a Times value with a kind outside the known enum members reached ToString.

Solutions

  1. Never construct Times via new Times(...) internals — only use the static factories (Exactly, AtLeast, Between, Once, Never, etc.)
  2. Check for mixed Moq assembly versions (binding redirects / NuGet unify to a single version)
  3. If hit without custom construction, it indicates corrupted state or a Moq bug — file an issue with a repro

Example fix

// before
var t = (Times)Activator.CreateInstance(typeof(Times), (Times.Kind)999, 0, 0); // invalid kind
// after
var t = Times.Exactly(3);
Defensive patterns

Strategy: type-guard

Validate before calling

// only build Times via public factories
Times t = Times.Exactly(3); // safe
// avoid: raw construction, casting ints to Times.Kind

Type guard

static bool IsValidTimes(Times t) =>
    new[] { "AtLeast", "AtLeastOnce", "AtMost", "AtMostOnce", "Between", "Exactly", "Once", "Never" }
        .Any(k => { try { return t.ToString().StartsWith(k); } catch (InvalidOperationException) { return false; } });

Try / catch

try
{
    Console.WriteLine(times);
}
catch (InvalidOperationException)
{
    // invalid Times kind — rebuild from a factory
    times = Times.AtLeastOnce();
}

Prevention

When it happens

Trigger: A Times struct created with an undefined Kind (e.g. invalid cast, default-initialized/partially constructed value, reflection or deserialization of garbage), then rendered via ToString or interpolated into a message.

Common situations: Custom test frameworks or serialization tools constructing Times incorrectly; binary/formatter deserialization of Moq internals; Moq version mismatches where an enum value from one version meets code from another.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at src/Moq/Times.cs:255

        {
            return !left.Equals(right);
        }

        /// <inheritdoc/>
        public override string ToString()
        {
            return this.kind switch
            {
                Kind.AtLeastOnce => "AtLeastOnce",
                Kind.AtLeast => $"AtLeast({this.from})",
                Kind.AtMost => $"AtMost({this.to})",
                Kind.AtMostOnce => "AtMostOnce",
                Kind.BetweenExclusive => $"Between({this.from - 1}, {this.to + 1}, Exclusive)",
                Kind.BetweenInclusive => $"Between({this.from}, {this.to}, Inclusive)",
                Kind.Exactly => $"Exactly({this.from})",
                Kind.Once => "Once",
                Kind.Never => "Never",
                _ => throw new InvalidOperationException(),
            };
        }

        internal string GetExceptionMessage(int callCount)
        {
            var (from, to) = this;

            if (this.kind == Kind.BetweenExclusive)
            {
                --from;
                ++to;
            }

            var message = this.kind switch
            {
                Kind.AtLeastOnce => Resources.NoMatchingCallsAtLeastOnce,
                Kind.AtLeast => Resources.NoMatchingCallsAtLeast,
                Kind.AtMost => Resources.NoMatchingCallsAtMost,

View on GitHub (pinned to 89a5be629c)