sebastianbergmann/phpunit · error · ComparisonMethodDoesNotAcceptParameterTypeException
%s is not an accepted argument type for comparison method %s
Error message
%s is not an accepted argument type for comparison method %s::%s().
What it means
The final precondition of assertObjectEquals(): PHPUnit takes the declared parameter type of the comparison method (resolving 'self' to the actual class) and requires the EXPECTED object passed to the assertion to be an instance of it, since it will be passed as the argument. If the expected object's class does not satisfy the parameter type, this exception is thrown instead of a type error at call time.
Source
Thrown at src/Framework/Constraint/Object/ObjectEquals.php:148
$type = $parameter->getType();
if (!$type instanceof ReflectionNamedType) {
throw new ComparisonMethodDoesNotDeclareParameterTypeException(
$other::class,
$this->method,
);
}
$typeName = $type->getName();
if ($typeName === 'self') {
// @codeCoverageIgnoreStart
$typeName = $other::class;
// @codeCoverageIgnoreEnd
}
if (!$this->expected instanceof $typeName) {
throw new ComparisonMethodDoesNotAcceptParameterTypeException(
$other::class,
$this->method,
$this->expected::class,
);
}
/** @phpstan-ignore method.dynamicName */
$result = $other->{$this->method}($this->expected);
assert(is_bool($result));
return $result;
}
protected function failureDescription(mixed $other): string
{
return $this->toString();
}View on GitHub (pinned to f123cdb2a2)
Solutions
- Make the expected object an instance of the type the comparison method accepts (usually the same class as actual): build the fixture with the same class
- If cross-class comparison is intended, widen the parameter type on equals() to a shared interface and ensure the expected object implements it
- Check you have not swapped the arguments: assertObjectEquals($expected, $actual, ...)
Example fix
// before $expected = new BaseMoney(500, 'EUR'); // BaseMoney $actual = new PaidMoney(500, 'EUR'); // subclass, equals(PaidMoney $other) $this->assertObjectEquals($expected, $actual); // after $expected = new PaidMoney(500, 'EUR'); $actual = new PaidMoney(500, 'EUR'); $this->assertObjectEquals($expected, $actual);
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the expected object satisfies the comparator's parameter type BEFORE asserting:
$param = (new ReflectionObject($actual))->getMethod('equals')->getParameters()[0];
$type = $param->getType()->getName();
$type = $type === 'self' ? $actual::class : $type;
if (!$expected instanceof $type) {
$this->markTestIncomplete(
sprintf('Expected must be %s, got %s', $type, $expected::class)
);
}
$this->assertObjectEquals($expected, $actual); Prevention
- Build the expected fixture from the same class (or subclass) as the actual value
- Keep argument order consistent: assertObjectEquals($expected, $actual, $method)
When it happens
Trigger: assertObjectEquals($expected, $actual) where $actual's equals() accepts self/SomeClass but $expected is of a different class — e.g. expected is a parent class instance, a sibling subclass, a mock/stub, or an entirely different DTO that happens to be structurally equal.
Common situations: Comparing a base-class fixture against a subclass actual; comparing a named vs anonymous/other-library representation of the same value; expected value replaced with a PHPUnit mock or prophecy stub of an unrelated interface; typo passing arguments swapped (expected/actual of different types).
Related errors
- Comparison method %s::%s() does not exist.
- Comparison method %s::%s() does not declare bool return type
- Comparison method %s::%s() does not declare exactly one para
- Parameter of comparison method %s::%s() does not have a decl
- getrusage() returned non-integer values for "%s" and/or "%s"
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/f241b376afcd5066.
Report an issue: GitHub.