pestphp/pest · error · OutOfRangeException

Sequence expectations are more than the iterable items.

Error message

Sequence expectations are more than the iterable items.

What it means

sequence() applies callbacks in order and wraps back to the first callback when items outnumber callbacks; the opposite direction is an error. After iterating, Pest throws OutOfRangeException if valuesCount < count($callbacks) — you declared more sequence expectations than the iterable has items (including the case where the iterable is empty and any callbacks were given).

Source

Thrown at src/Expectation.php:230

            throw new InvalidArgumentException('No sequence expectations defined.');
        }

        $index = $valuesCount = 0;

        foreach ($this->value as $key => $value) {
            $valuesCount++;

            if ($callbacks[$index] instanceof Closure) {
                $callbacks[$index](new self($value), new self($key));
            } else {
                new self($value)->toEqual($callbacks[$index]);
            }

            $index = isset($callbacks[$index + 1]) ? $index + 1 : 0;
        }

        if ($valuesCount < count($callbacks)) {
            throw new OutOfRangeException('Sequence expectations are more than the iterable items.');
        }

        return $this;
    }

    /**
     * @template TMatchSubject of array-key
     *
     * @param  (callable(): TMatchSubject)|TMatchSubject  $subject
     * @param  array<TMatchSubject, (callable(self<TValue>): mixed)|TValue>  $expressions
     * @return self<TValue>
     */
    public function match(mixed $subject, array $expressions): self
    {
        $subject = $subject instanceof Closure ? $subject() : $subject;

        $matched = false;

View on GitHub (pinned to 1af74a215c)

Solutions

  1. Match the counts: remove surplus sequence entries so count(callbacks) <= count(items).
  2. If the item count is legitimately variable, rely on wrap-around: keep only as many callbacks as the guaranteed prefix and let the last one repeat.
  3. Fix the data producer so it returns the full expected set (e.g., correct the query/mocking that dropped rows).
  4. Assert the size first: expect($items)->toHaveCount(3) before sequence() to fail with a clearer message.

Example fix

// before
expect([1, 2])->sequence(
    fn ($v) => $v->toBe(1),
    fn ($v) => $v->toBe(2),
    fn ($v) => $v->toBe(3), // more expectations than items
);
// after
expect([1, 2])->sequence(
    fn ($v) => $v->toBe(1),
    fn ($v) => $v->toBe(2),
);
Defensive patterns

Strategy: validation

Validate before calling

$callbacks = [/* ... */];
$items = [...];
if (count($items) < count($callbacks)) {
    throw new LogicException(
        'sequence() needs at least as many items ('.count($items).') as expectations ('.count($callbacks).')'
    );
}
expect($items)->sequence(...$callbacks);

Prevention

When it happens

Trigger: expect([1, 2])->sequence(fn ($v) => $v->toBe(1), fn ($v) => $v->toBe(2), fn ($v) => $v->toBe(3)); expect([])->sequence(fn ($v) => ...); a dataset/pagination result with fewer rows than the expected sequence; off-by-one when counting items.

Common situations: API responses that return fewer records than expected (filtered/empty results); mocks or factories configured to produce fewer entities than the test's sequence asserts; forgetting that sequence wraps — the LAST callback repeats for surplus items, so extra expectations cannot be absorbed.

Related errors


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