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): ArchExpectationView on GitHub (pinned to 1af74a215c)
Solutions
- 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.
- 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).
- 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
- Prefer the most specific negated assertion (not->toBeNull, not->toContain) over broad ones (not->toBe) so failures are actionable.
- When writing guard assertions, first assert the happy path failed: check the error state before asserting its absence.
- Keep negated assertions close to the act that produced the value — long chains hide which ->not failed.
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
- Cached failure
- Expectation value is not iterable.
- No sequence expectations defined.
- Sequence expectations are more than the iterable items.
- Unhandled match value.
AI-assisted analysis of pestphp/pest@1af74a215c (2026-08-21).
Data as JSON: /api/errors/744751135986c4b4.
Report an issue: GitHub.