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
- Never construct Times via new Times(...) internals — only use the static factories (Exactly, AtLeast, Between, Once, Never, etc.)
- Check for mixed Moq assembly versions (binding redirects / NuGet unify to a single version)
- 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
- Construct Times only via its static factories
- Keep a single Moq package version across projects
- Never persist/deserialize Times values
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
- InvalidOperationException (unhandled Times kind in…
- Unsupported expression
- Could not determine the correct positions for all argument…
- The return type of the last member shown above is not…
- Value cannot be null. (Parameter 'value')
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)