{"record":{"id":"8f37a8d871301b71","repo":"pestphp/pest","slug":"no-sequence-expectations-defined","errorCode":null,"errorMessage":"No sequence expectations defined.","messagePattern":"No sequence expectations defined\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Expectation.php","lineNumber":212,"sourceCode":"        }\n\n        return new EachExpectation($this);\n    }\n\n    /**\n     * @template TSequenceValue\n     *\n     * @param  (callable(self<TValue>, self<string|int>): void)|TSequenceValue  ...$callbacks\n     * @return self<TValue>\n     */\n    public function sequence(mixed ...$callbacks): self\n    {\n        if (! is_iterable($this->value)) {\n            throw new BadMethodCallException('Expectation value is not iterable.');\n        }\n\n        if ($callbacks === []) {\n            throw new InvalidArgumentException('No sequence expectations defined.');\n        }\n\n        $index = $valuesCount = 0;\n\n        foreach ($this->value as $key => $value) {\n            $valuesCount++;\n\n            if ($callbacks[$index] instanceof Closure) {\n                $callbacks[$index](new self($value), new self($key));\n            } else {\n                new self($value)->toEqual($callbacks[$index]);\n            }\n\n            $index = isset($callbacks[$index + 1]) ? $index + 1 : 0;\n        }\n\n        if ($valuesCount < count($callbacks)) {\n            throw new OutOfRangeException('Sequence expectations are more than the iterable items.');","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/pestphp/pest/blob/1af74a215c3a89bc7a44fc6f9322e369eaad2423/src/Expectation.php#L194-L230","documentation":"expect($value)->sequence() with zero arguments throws InvalidArgumentException immediately after the iterable check passes. sequence() exists to assert item-by-item order, so Pest rejects an empty expectation list as a no-op rather than silently passing. The fix is to supply at least one closure or expected value.","triggerScenarios":"expect($items)->sequence(); building the callbacks list dynamically from data that ends up empty ($callbacks = []; ->sequence(...$callbacks)); copy-pasting a sequence() call and deleting its body; intending each() (single callback for all items) and calling sequence() instead.","commonSituations":"Data-driven tests that compute expected sequences and occasionally receive an empty expectation set; refactors where the sequence body was removed but the call remained; misunderstanding the difference between each() and sequence().","solutions":["Pass at least one closure or expected value: ->sequence(fn ($v) => $v->toBe(1)).","If every item should satisfy the same expectation, use each() instead of sequence().","When generating callbacks dynamically, guard the empty case: if ($expected === []) { expect($items)->toBeEmpty(); return; }."],"exampleFix":"// before\nexpect($logs)->sequence(...$expectedPatterns); // $expectedPatterns is []\n// after\nif ($expectedPatterns === []) {\n    expect($logs)->toBeEmpty();\n} else {\n    expect($logs)->sequence(...$expectedPatterns);\n}","handlingStrategy":"validation","validationCode":"if ($expectedPatterns === []) {\n    expect($items)->toBeEmpty();\n} else {\n    expect($items)->sequence(...$expectedPatterns);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use each() when one callback covers all items; reserve sequence() for ordered per-item assertions.","When building sequence callbacks from data, fail fast on an empty expectation list with a clear message.","Lint test helpers that spread dynamic arrays into sequence(...$x) without an empty guard."],"tags":["pest","expectation","sequence","empty-arguments","validation"],"backgroundTag":"missing-required-arguments","analyzedSha":"1af74a215c3a89bc7a44fc6f9322e369eaad2423","analyzedAt":"2026-08-21T02:16:38.132Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}