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

  1. Pass a Closure that returns the generator: new LazyCollection(fn () => $this->rows()).
  2. Pass the function reference without invoking: new LazyCollection([$this, 'rows']).
  3. 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

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


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/9c130638c61bb93d.json. Report an issue: GitHub.