sebastianbergmann/phpunit · error · DuplicateMethodException

Cannot double using a method list that contains duplicates:

Error message

Cannot double using a method list that contains duplicates: "%s" (duplicate: "%s")

What it means

Thrown by Generator::ensureValidMethods() when the method list for a test double fails the $methods !== array_unique($methods) check, i.e. the same method name appears twice. PHPUnit refuses to generate a double whose method list has duplicates because the generated class would define colliding methods.

Source

Thrown at src/Framework/MockObject/Generator/Generator.php:720

     * @param ?list<non-empty-string> $methods
     *
     * @throws DuplicateMethodException
     * @throws InvalidMethodNameException
     */
    private function ensureValidMethods(?array $methods): void
    {
        if ($methods === null) {
            return;
        }

        foreach ($methods as $method) {
            if (preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', (string) $method) === 0) {
                throw new InvalidMethodNameException((string) $method);
            }
        }

        if ($methods !== array_unique($methods)) {
            throw new DuplicateMethodException($methods);
        }
    }

    /**
     * @throws InvalidClassNameException
     */
    private function ensureValidNameForTestDoubleClass(string $className): void
    {
        if ($className === '') {
            return;
        }

        if (preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', $className) === 0) {
            throw new InvalidClassNameException($className);
        }
    }

    /**

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Remove the duplicate entry reported in the message (the message names both the list and the duplicate).
  2. If merging lists dynamically, wrap with array_values(array_unique($methods)) before passing to onlyMethods()/addMethods().
  3. Check you did not pass the same method via both onlyMethods() and addMethods() on the same MockBuilder.

Example fix

// before
$mock = $this->getMockBuilder(C::class)
    ->onlyMethods(['load', 'save', 'load'])
    ->getMock();

// after
$mock = $this->getMockBuilder(C::class)
    ->onlyMethods(['load', 'save'])
    ->getMock();
Defensive patterns

Strategy: validation

Validate before calling

$methods = array_values(array_unique($methods));
if (count($methods) !== count(array_unique($methods))) {
    throw new InvalidArgumentException('duplicates in method list');
}

Type guard

function hasNoDuplicates(array $methods): bool
{
    return count($methods) === count(array_unique($methods));
}

Try / catch

try {
    $mock = $builder->onlyMethods($methods)->getMock();
} catch (PHPUnit\Framework\MockObject\DuplicateMethodException $e) {
    // deduplicate and retry with array_values(array_unique($methods))
}

Prevention

When it happens

Trigger: onlyMethods(['foo', 'foo']) or addMethods(['bar', 'bar']); merging two arrays for the method list where the same name occurs in both, e.g. ->onlyMethods(array_merge($baseMethods, $extraMethods)) with overlapping entries; a data provider that repeats a name.

Common situations: Combining a base list of mocked methods with an extra list and forgetting to deduplicate; copy-paste duplication inside a long onlyMethods() array; lists assembled from multiple sources (config + hardcoded) in test helpers.

Related errors


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