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

  1. Wrap raw values with equalTo(), identicalTo(), or sameValue()
  2. Ensure every array element is a Matcher instance before constructing allOf/anyOf
  3. 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

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


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 item

View on GitHub (pinned to aa726aeff9)