hamcrest/hamcrest-php · error · InvalidArgumentException
Each argument or element must be a Hamcrest matcher
Error message
Each argument or element must be a Hamcrest matcher
What it means
Hamcrest's Util::checkAllAreMatchers() validates that every element passed to aggregate matchers (allOf, anyOf, etc.) implements the Matcher interface. A non-matcher value (raw value, string, null) is rejected with InvalidArgumentException at construction time.
Solutions
- Wrap raw values with equalTo(), identicalTo(), or sameValue()
- Ensure every array element is a Matcher instance before constructing allOf/anyOf
- Use Util::wrapValueWithIsEqual() (as assertThat does) for dynamic values
Example fix
// before
assertThat($value, allOf('a', $b));
// after
assertThat($value, allOf(equalTo('a'), $b)); Defensive patterns
Strategy: type-guard
Validate before calling
foreach ($candidates as $c) {
if (!$c instanceof \Hamcrest\Matcher) {
throw new PreconditionException('not a Matcher: '.gettype($c));
}
} Type guard
function allAreMatchers(array $ms): bool {
return array_reduce($ms, fn($ok, $m) => $ok && $m instanceof \Hamcrest\Matcher, true);
} Try / catch
try {
assertThat($v, allOf(...$matchers));
} catch (\InvalidArgumentException $e) {
if (strpos($e->getMessage(), 'Hamcrest matcher') === false) throw $e;
fail('One of the combined values is not a Matcher; wrap literals with equalTo()');
} Prevention
- Always wrap expected literals in equalTo()/identicalTo()
- Import matcher functions so a missing import doesn't resolve to a plain value
- Run static analysis; Hamcrest matcher params can be typed against Matcher
- Write a small test asserting each element of shared matcher lists implements Matcher
When it happens
Trigger: Passing a plain value instead of a matcher, e.g. allOf('a', 'b'), anyOf([$anArray, 'x']), or including null in the matcher list.
Common situations: Forgetting equalTo()/identicalTo() wrappers around literal expected values; mixing raw values into matcher arrays; older code written for APIs that auto-wrapped values.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Must pass an object, array, or class name
- assertThat() requires one to three arguments
- Must pass a valid XML document
- Must pass a valid HTML or XHTML document
AI-assisted analysis of hamcrest/hamcrest-php@aa726aeff9 (2026-09-15).
Data as JSON: /api/errors/656ed6043f114aa9.
Report an issue: GitHub.
Appendix: source
Thrown at hamcrest/Hamcrest/Util.php:44
public static function wrapValueWithIsEqual($item)
{
return ($item instanceof Matcher)
? $item
: Core\IsEqual::equalTo($item)
;
}
/**
* Throws an exception if any item in $matchers is not a Hamcrest\Matcher.
*
* @param array<mixed> $matchers expected to contain only matchers
* @throws \InvalidArgumentException if any item is not a matcher
*/
public static function checkAllAreMatchers(array $matchers): void
{
foreach ($matchers as $m) {
if (!($m instanceof Matcher)) {
throw new \InvalidArgumentException(
'Each argument or element must be a Hamcrest matcher'
);
}
}
}
/**
* Returns a copy of $items where each non-Matcher item is replaced by
* a Hamcrest\Core\IsEqual matcher for the item. If the first and only item
* is an array, it is used as the $items array to support the old style
* of passing an array as the sole argument to a matcher.
*
* @param array<mixed> $items contains items and matchers
* @return array<Matcher> all items are
*/
public static function createMatcherArray(array $items)
{
//Extract single array itemView on GitHub (pinned to aa726aeff9)