Mockito throws InvalidUseOfMatchersException when a stubbed call mixes an argument matcher such as ArgumentMatchers.anyInt() with a plain literal argument. Explain the rule this violates and how Mockito's argument matchers are implemented under the hood.
answer
- Matchers = side effect on a thread-local stack
- Return dummy 0/false/null, not the value
- 0 matchers or N matchers, never in between
- eq() promotes a literal to a matcher
- N matchers expected, M recorded
basics
~20 sMatchers do not return values you pass in. Each one pushes a matcher object onto a thread-local stack and returns a dummy (0, false, null). Mockito only sees dummies, so per call all arguments must be matchers or none. Wrap literals in eq().
solid answer
~50 sMockito matchers are **side effects**, not values. Calling `anyInt()` registers an `ArgumentMatcher` on a thread-local stack held by Mockito's `MockingProgress`, then returns a dummy default (`0`); `eq("abc")` registers an equality matcher and returns `null`. The mock method is then invoked with those dummies, so when Mockito intercepts the invocation it cannot tell which position carried a real value and which carried a registered matcher. All it has is a stack of N matchers and a list of M arguments. Hence the **all-or-none rule**: within one invocation, either every argument is a matcher or none is. If the matcher count is non-zero and does not equal the argument count, Mockito throws `InvalidUseOfMatchersException` saying something like "2 matchers expected, 1 recorded". The fix is never to drop the matcher you need, but to lift the literals into matchers: `when(repo.find(anyInt(), eq("abc")))`. Same rule applies to `verify(...)`.
code
java · 8 lines// throws InvalidUseOfMatchersException: 2 matchers expected, 1 recorded
when(repo.find(anyInt(), "abc")).thenReturn(user);
// legal: all matchers
when(repo.find(anyInt(), eq("abc"))).thenReturn(user);
// also legal: no matchers at all
when(repo.find(42, "abc")).thenReturn(user);go deeper
Recall the rule and the fix: matchers and raw values cannot be mixed in one call; wrap the literals in eq().
Explain the mechanism - thread-local matcher stack, dummy return values, pairing only defined at 0 or N matchers - and that stubbing and verification behave identically.
Add the operational consequences: dirty stack leaking into the next test, thread-locality breaking cross-thread stubbing, and why fail-fast is preferable to a guessed pairing.
Frame it as an API-design tradeoff: Mockito buys a fluent, compile-checked call syntax by smuggling state through a thread-local, and the all-or-none rule is the price. Contrast with matcher-object APIs (Hamcrest-style, MockK) that avoid the ambiguity but lose the natural call shape.
## The failure ``` org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 2 matchers expected, 1 recorded ``` This comes from code like `when(repo.find(anyInt(), "abc")).thenReturn(x)` - one matcher and one literal in a two-argument call. ## Why matchers cannot be mixed Java evaluates arguments before the method call. Mockito has no way to wrap an expression such as `anyInt()` in metadata: whatever it returns is just an `int`. So Mockito uses a trick. `ArgumentMatchers.anyInt()` does two things: 1. It pushes an `ArgumentMatcher` instance onto a stack (`ArgumentMatcherStorage`) held in a `ThreadLocal` inside Mockito's `MockingProgress`. 2. It returns the type's default value - `0` for `int`, `false` for `boolean`, `null` for objects. Then `repo.find(0, "abc")` actually executes on the mock. The mock's interceptor now has: an invocation with arguments `[0, "abc"]`, and a matcher stack containing one entry. It must build a `InvocationMatcher` pairing one matcher per argument. Mockito's rule for pairing is deliberately simple: - **Zero matchers recorded** - treat every argument as an `Equals` matcher (the common `when(repo.find(1, "abc"))` case). - **Matcher count equals argument count** - pair them positionally. - **Anything else** - it is ambiguous, so fail fast with `InvalidUseOfMatchersException`. It is ambiguous because Mockito genuinely cannot know whether the recorded matcher belonged to argument 0 or argument 1: both slots contain plausible values, and `0` is both a legal literal and the dummy left behind by `anyInt()`. Guessing would produce tests that silently match the wrong calls, which is worse than an exception. ## The fix: eq() Promote every literal to a matcher with `ArgumentMatchers.eq(...)`: ```java when(repo.find(anyInt(), eq("abc"))).thenReturn(x); verify(repo).find(eq(42), any(Filter.class)); ``` `eq(x)` registers an `Equals` matcher that calls `x.equals(actual)` - semantically identical to passing the literal, but it participates in the matcher stack so the counts line up. If no argument needs a wildcard, drop matchers entirely and pass plain values; do not decorate everything with `eq()` for its own sake, it only adds noise. ## Consequences worth knowing **The rule is per invocation, not per test.** `when(a.f(anyInt()))` followed by `when(b.g(1, "x"))` is fine; each call is validated separately. **Stubbing and verification share the mechanism.** The identical rule and identical exception apply to `verify(mock).method(...)`. **The stack is thread-local.** Matchers registered on one thread are invisible to another, which is why stubbing from a worker thread while asserting on the main thread produces bizarre matcher errors. **Failure can surface late.** If matchers are registered but the mock call never happens (see misplaced-matcher scenarios), the stack stays dirty and the exception is thrown by the *next* mock interaction - possibly in a different test method. Mockito's `validateMockitoUsage()` and the `MockitoExtension` exist partly to report this at the right place. **Kotlin/`null` note.** `eq()` and `any()` return `null` for reference types, which is why calling them against non-null Kotlin parameters needs `mockito-kotlin` helpers - the dummy return is the whole reason. ## Interview framing The expected answer is not "because Mockito says so". It is: matchers communicate through a side-effect stack and return dummies, positional pairing is only unambiguous at 0 or N matchers, so Mockito refuses partial sets, and `eq()` is the escape hatch that turns a literal into a stack entry.
- Does the same rule apply to verify(), or only to when()?It applies identically to both, because both go through the same invocation-interception path and the same thread-local matcher stack. `verify(repo).find(anyInt(), "abc")` fails with the same InvalidUseOfMatchersException. The only difference is that a verification failure is easier to misread as an assertion problem.
- Is eq(x) exactly equivalent to passing x directly?Semantically yes for matching - `eq(x)` registers an `Equals` matcher that uses `x.equals(actual)`, which is what Mockito applies to raw arguments anyway. The difference is bookkeeping: `eq(x)` also pushes an entry on the matcher stack so the counts balance. Use it only when the same call already needs another matcher.
- Why does the exception sometimes point at a test that looks completely correct?Because matchers registered without a following mock invocation leave the stack dirty, and validation happens on the next mock interaction - which may be a later test method in the same class or thread. Running with MockitoExtension or calling Mockito.validateMockitoUsage() in teardown attributes the misuse to the test that actually caused it.
Matchers are like leaving sticky notes on a counter while handing over blank envelopes. The clerk sees one note and two envelopes and cannot tell which envelope the note describes, so refuses the whole transaction.
saying these in an interview costs you the question
- Claiming anyInt() returns a special matcher object that Mockito inspects, rather than a dummy value plus a stack side effect
- Fixing the error by deleting the matcher and hardcoding a value, losing the intended wildcard
- Believing the rule is per test method or per mock rather than per single invocation
- Wrapping every argument in eq() everywhere, including calls that use no matchers at all
- Saying Mockito could match positionally if it wanted - ignoring that the dummy value is indistinguishable from a real literal