pestphp/pest · error · BadMethodCallException

Method [%s] does not exist in [%s].

Error message

Method [%s] does not exist in [%s].

What it means

When you call an unknown method on an Expectation, Pest's __call tries three routes: a registered expectation, forwarding to PendingArchExpectation for arch-style methods (only when the value is not an object), or proxying to a real method on the underlying object (higher-order). If the method is none of those and the value is not an object, you get BadMethodCallException naming the method and the value's type. Typically this means a misspelled expectation name applied to a scalar/array/null value.

Source

Thrown at src/Expectation.php:320

        return $this;
    }

    /**
     * @param  array<int, mixed>  $parameters
     * @return Expectation<TValue>|HigherOrderExpectation<Expectation<TValue>, TValue>
     */
    public function __call(string $method, array $parameters): Expectation|HigherOrderExpectation|PendingArchExpectation|ArchExpectation
    {
        if (! self::hasMethod($method)) {
            if (! is_object($this->value) && method_exists(PendingArchExpectation::class, $method)) {
                $pendingArchExpectation = new PendingArchExpectation($this, []);

                return $pendingArchExpectation->$method(...$parameters); // @phpstan-ignore-line
            }

            if (! is_object($this->value)) {
                throw new BadMethodCallException(sprintf(
                    'Method [%s] does not exist in [%s].',
                    $method,
                    gettype($this->value)
                ));
            }

            /* @phpstan-ignore-next-line */
            return new HigherOrderExpectation($this, call_user_func_array($this->value->$method(...), $parameters));
        }

        $closure = $this->getExpectationClosure($method);
        $reflectionClosure = new \ReflectionFunction($closure);
        $expectation = $reflectionClosure->getClosureThis();

        if ($reflectionClosure->getReturnType()?->__toString() === ArchExpectation::class) {
            return $closure(...$parameters);
        }

View on GitHub (pinned to 1af74a215c)

Solutions

  1. Check the exact spelling against Pest's expectation API for your installed version (composer show pestphp/pest).
  2. If it is a custom expectation, make sure expect()->extend(...) runs before use — e.g., the file is listed in the tests directory structure Pest auto-loads (Expectations.php).
  3. For object proxies, ensure the underlying value really is an object with that method; for arrays/scalars, use the array/scalar expectation instead.
  4. If you need the method to exist, register it: expect()->extend('toFoo', fn () => ...).

Example fix

// before
expect('pest')->toUppercase(); // BadMethodCallException
// after
expect('PEST')->toBeUppercase();
Defensive patterns

Strategy: type-guard

Validate before calling

use Pest\Expectation;

if (! Expectation::hasMethod('toFoo')) {
    expect()->extend('toFoo', fn (mixed $arg = null) => /* ... */);
}
expect($value)->toFoo();

Type guard

// object-proxy path: verify the underlying object has the method
if (is_object($value) && method_exists($value, 'getName')) {
    expect($value)->getName()->toBe('Pest');
} else {
    expect($value)->toBeObject(); // fail with a clear message
}

Prevention

When it happens

Trigger: expect('foo')->toUpercase() (misspelled toBeUppercase); expect(5)->toHaveItems(3) (method exists only on the object proxy path); calling a custom expectation before it was registered with expect()->extend(); calling an object-proxied method (e.g., ->getName()) on a scalar or array.

Common situations: Typos in expectation names (toBeTuure, toEqualRecursive); upgrading Pest and using an expectation introduced in a newer version; custom expectations defined in a Helpers/Expectations.php file that is not loaded; assuming an object-style proxy works on arrays.

Related errors


AI-assisted analysis of pestphp/pest@1af74a215c (2026-08-21). Data as JSON: /api/errors/74e7b233c8221b49. Report an issue: GitHub.