laravel/framework · error · InvalidArgumentException
Generators should not be passed directly to LazyCollection.
Error message
Generators should not be passed directly to LazyCollection. Instead, pass a generator function.
What it means
Thrown by the LazyCollection constructor when a Generator instance is passed directly instead of a Closure that produces a generator. LazyCollection is lazy precisely because it wraps a factory (Closure) it can invoke multiple times; a bare Generator is single-use and would be exhausted on first iteration, breaking re-iteration. Passing it as a function preserves reusability.
Source
Thrown at src/Illuminate/Collections/LazyCollection.php:54
* @var (Closure(): \Generator<TKey, TValue, mixed, void>)|static|array<TKey, TValue>
*/
public $source;
/**
* Create a new lazy collection instance.
*
* @param \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>|(Closure(): \Generator<TKey, TValue, mixed, void>)|self<TKey, TValue>|array<TKey, TValue>|null $source
*
* @throws \InvalidArgumentException
*/
public function __construct($source = null)
{
if ($source instanceof Closure || $source instanceof self) {
$this->source = $source;
} elseif (is_null($source)) {
$this->source = static::empty();
} elseif ($source instanceof Generator) {
throw new InvalidArgumentException(
'Generators should not be passed directly to LazyCollection. Instead, pass a generator function.'
);
} else {
$this->source = $this->getArrayableItems($source);
}
}
/**
* Create a new instance of the collection.
*
* @param \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>|(Closure(): \Generator<TKey, TValue, mixed, void>)|self<TKey, TValue>|array<TKey, TValue>|null $items
* @return static
*/
protected function newInstance($items = [])
{
return new static($items);
}
View on GitHub (pinned to bd6b5437e6)
Solutions
- Pass a Closure that returns the generator: new LazyCollection(fn () => $this->rows()).
- Pass the function reference without invoking: new LazyCollection([$this, 'rows']).
- If re-iteration isn't needed, materialize with collect() or pass an array instead.
Example fix
// before $lazy = new LazyCollection($this->generateRows()); // after $lazy = new LazyCollection(fn () => $this->generateRows());
Defensive patterns
Strategy: type-guard
Validate before calling
if ($source instanceof \Generator) {
$original = $source;
$source = fn () => $original; // wrap into a factory
}
$lazy = new \Illuminate\Support\LazyCollection($source); Type guard
function isGeneratorFactory($src): bool {
return $src instanceof \Closure || $src instanceof \Illuminate\Support\LazyCollection || ! ($src instanceof \Generator);
} Try / catch
try {
$lazy = new \Illuminate\Support\LazyCollection($src);
} catch (\InvalidArgumentException $e) {
$lazy = new \Illuminate\Support\LazyCollection(fn () => $src);
} Prevention
- Always pass a Closure (fn () => generator) to LazyCollection, never an invoked generator.
- Static-analyze with PHPStan/Psalm at the LazyCollection constructor to catch Generator args.
When it happens
Trigger: new LazyCollection(my_generator_function()) where the parens invoke the generator. Or LazyCollection::make($gen) with $gen already a Generator. Anywhere a yield-based function is called rather than referenced.
Common situations: Writing new LazyCollection(function () { yield ... }) but accidentally calling another generator function inline: new LazyCollection($this->rows()). Also wrapping an existing iterator/generator from a third-party library directly.
Related errors
- Step value cannot be zero.
- Step value must be at least 1.
- Size value must be at least 1.
- Number of groups must be at least 1.
- Number of groups must be at least 1.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/9c130638c61bb93d.json.
Report an issue: GitHub.