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

  1. Use one matcher plus argument-dependent returns: ->method('get')->willReturnMap([[1, 'a'], [2, 'b']]).
  2. Or use ->willReturnCallback(fn (int $id) => match ($id) { 1 => 'a', 2 => 'b' }).
  3. If you truly need two separate argument assertions, keep them on different methods, or assert a parameter set once via withParameterSetsInAnyOrder([...]).
  4. 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

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


AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23). Data as JSON: /api/errors/fd9d777b5a97c4da. Report an issue: GitHub.