pestphp/pest · error · ExpectationFailedException

Expecting %s not %s %s.

Error message

Expecting %s not %s %s.

What it means

This is the runtime assertion failure raised by negated expectations: when you chain ->not (or use a toNot* method), the opposite expectation succeeds only if the underlying assertion FAILS. If the value actually satisfies the expectation, Pest throws ExpectationFailedException with 'Expecting {value} not {assertion} {args}.' — i.e., the test proved the opposite of what you asserted.

Source

Thrown at src/Expectations/OppositeExpectation.php:670

            $this->original->{$name}; // @phpstan-ignore-line
        } catch (ExpectationFailedException) {
            return $this->original;
        }

        $this->throwExpectationFailedException($name);
    }

    /**
     * @param  array<int, mixed>|string  $arguments
     */
    public function throwExpectationFailedException(string $name, array|string $arguments = []): never
    {
        $arguments = is_array($arguments) ? $arguments : [$arguments];

        $exporter = Exporter::default();

        throw new ExpectationFailedException(sprintf(
            'Expecting %s not %s %s.',
            $exporter->shortenedExport($this->original->value),
            strtolower((string) preg_replace('/(?<!\ )[A-Z]/', ' $0', $name)),
            implode(' ', array_map(fn (mixed $argument): string => $exporter->export($argument), $arguments)),
        ));
    }

    public function toHaveConstructor(): ArchExpectation
    {
        return $this->toHaveMethod('__construct');
    }

    public function toHaveDestructor(): ArchExpectation
    {
        return $this->toHaveMethod('__destruct');
    }

    private function toBeBackedEnum(string $backingType): ArchExpectation

View on GitHub (pinned to 1af74a215c)

Solutions

  1. Read the message: it names the value, the negated assertion, and the arguments — that tells you exactly which expectation failed; then fix the code under test so the negation actually holds.
  2. If the value is legitimately expected to match, the assertion itself is wrong: remove ->not or turn it into the positive form (toBe instead of not->toBe).
  3. For status/guard checks, prefer the most specific negated assertion available (not->toBeEmpty, not->toBeNull) over broad ones (not->toBe) to make failures actionable.

Example fix

// before
it('does not log errors', function () {
    expect($this->logger->lines)->not->toBeEmpty(); // failed: Expecting [...] not to be empty.
});
// after
it('does not log errors', function () {
    expect($this->logger->lines)->toBeEmpty();
});
Defensive patterns

Strategy: try-catch

Try / catch

use PHPUnit\Framework\ExpectationFailedException;

it('assertion actually fails as expected', function () {
    try {
        expect($value)->not->toBeEmpty();
        $this->fail('Negated expectation should have failed');
    } catch (ExpectationFailedException $e) {
        // expected path — the value WAS empty
        expect($e->getMessage())->toContain('not to be empty');
    }
});

Prevention

When it happens

Trigger: expect($count)->not->toBe(0) when $count is 0; expect($response->status())->not->toBe(200) on a successful response; ->not->toContain('error') when the string does contain 'error'; ->not->toBeNull() applied to a null value.

Common situations: Guard assertions (asserting an error did NOT occur) that fire because the error did occur; negative assertions written optimistically; copy-pasting a not from another test; values changing type after refactors (0 == null style surprises with toBeFalse/not->toBeTrue pairs).

Related errors


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