sebastianbergmann/phpunit · error · MethodParametersAlreadyConfiguredForAnotherMatcherException
Parameters for method "%s" are already configured for anothe
Error message
Parameters for method "%s" are already configured for another matcher. with() configures an expectation (the method must be called with the specified arguments), it does not select a return value based on arguments. Use willReturnMap() to return different values based on arguments.
What it means
Thrown by InvocationMockerImplementation when you call with() (or the parameter-set variants / withAnyParameters()) on a matcher whose method already has a parameters rule on a DIFFERENT matcher of the same double. In PHPUnit's model, with() declares 'the method must be called with these arguments' (an assertion), not 'return X for args Y', so two conflicting argument assertions for one method are rejected. The message points you to willReturnMap() for argument-dependent returns.
Source
Thrown at src/Framework/MockObject/Runtime/InvocationMockerImplementation.php:130
*
* @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537
*/
public function after(string $id): InvocationMocker
{
$this->matcher->setAfterMatchBuilderId($id);
return $this;
}
/**
* @throws MethodParametersAlreadyConfiguredForAnotherMatcherException
*/
private function ensureNoOtherMatcherHasParametersRuleForSameMethod(): void
{
foreach ($this->configurableMethods as $method) {
if ($this->matcher->methodNameRule()->matchesName($method->name()) &&
$this->invocationHandler->hasMatcherWithParametersRuleForMethodName($this->matcher, $method->name())) {
throw new MethodParametersAlreadyConfiguredForAnotherMatcherException($method->name());
}
}
}
private function emitDeprecationWhenCreatedWithoutExplicitExpects(): void
{
if (!$this->createdWithoutExplicitExpects) {
return;
}
EventFacade::emitter()->testTriggeredPhpunitDeprecation(
null,
'Using with*() without expects() is deprecated and will no longer be possible in PHPUnit 14.',
);
}
}
View on GitHub (pinned to f123cdb2a2)
Solutions
- Use one matcher plus argument-dependent returns: ->method('get')->willReturnMap([[1, 'a'], [2, 'b']]).
- Or use ->willReturnCallback(fn (int $id) => match ($id) { 1 => 'a', 2 => 'b' }).
- If you truly need two separate argument assertions, keep them on different methods, or assert a parameter set once via withParameterSetsInAnyOrder([...]).
- Remove a redundant withAnyParameters()/with() left over on an earlier matcher for the same method.
Example fix
// before
$cache = $this->createMock(Cache::class);
$cache->expects($this->any())->method('get')->with('a')->willReturn(1);
$cache->expects($this->any())->method('get')->with('b')->willReturn(2);
// after
$cache = $this->createMock(Cache::class);
$cache->method('get')->willReturnMap([
['a', 1],
['b', 2],
]); Defensive patterns
Strategy: validation
Validate before calling
// one argument assertion per method: encode lookup tables as maps instead
$cases = [[1, 'a'], [2, 'b']];
$mock->method('get')->willReturnMap($cases); // no second with() needed Type guard
function assertSingleWithPerMethod(array $expectationsByMethod): bool
{
foreach (array_count_values(array_keys($expectationsByMethod)) as $count) {
if ($count > 1) {
return false;
}
}
return true;
} Try / catch
try {
$mock->expects($this->once())->method('get')->with(2)->willReturn('b');
} catch (PHPUnit\Framework\MockObject\MethodParametersAlreadyConfiguredForAnotherMatcherException $e) {
// merge both argument cases into willReturnMap() on the existing matcher
} Prevention
- Treat with() as an assertion, not a dispatch table — argument-dependent returns belong in willReturnMap()/willReturnCallback().
- One with() (or one parameter-set rule) per method per double.
- When migrating Mockery/Prophecy-style tests, rewrite per-argument expectations as maps immediately.
When it happens
Trigger: $mock->expects($this->once())->method('get')->with(1)->willReturn('a'); $mock->expects($this->once())->method('get')->with(2)->willReturn('b'); — second with() for method 'get' throws. Also triggered by mixing with() with withParameterSetsInOrder()/withParameterSetsInAnyOrder()/withParameterSetsInPartialOrder()/withAnyParameters() for the same method on another matcher.
Common situations: Trying to express a lookup table (same method, different arguments, different returns) the way developers do in prophecy/mockery; migrating such tests to PHPUnit 10+ where this restriction is enforced; combining an argument assertion from a copied test with a newly written one for the same method.
Related errors
- Expectation for %s failed. %s
- Cannot double method with invalid name "%s"
- Cannot double using a method list that contains duplicates:
- Cannot use "%s" as the name of a test double class because i
- The name "%s" is already in use
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/fd9d777b5a97c4da.
Report an issue: GitHub.