laravel/framework · error · InvalidArgumentException

The provided class must extend…

Error message

The provided class must extend [Illuminate\Support\Collection].

What it means

Thrown by the AsCollection cast when the first argument (the custom collection class name) does not extend Illuminate\Support\Collection. The cast uses is_a() with allow_string=true to verify the class is a subclass before instantiating it; any class that is not a Collection descendant fails this check. This protects the cast from producing an object that lacks the Collection API the rest of Eloquent expects.

Solutions

  1. Verify the class passed as the first argument extends Illuminate\Support\Collection (use is_subclass_of($class, \Illuminate\Support\Collection::class)).
  2. Add the correct `use` import for the collection class and confirm the fully-qualified name in the cast definition.
  3. If you only need a base collection, drop the custom class argument and use AsCollection::class alone.
  4. If you need a custom class, make it `class MyCollection extends \Illuminate\Support\Collection`.

Example fix

// before
protected $casts = [
    'items' => AsCollection::class . ':' . App\Support\ItemBag::class, // ItemBag does not extend Collection
];

// after
class ItemBag extends \Illuminate\Support\Collection {}

protected $casts = [
    'items' => AsCollection::class . ':' . App\Support\ItemBag::class,
];
Defensive patterns

Strategy: validation

Validate before calling

use Illuminate\Support\Collection;

$collectionClass = App\Support\MyCollection::class; // candidate
if (! is_subclass_of($collectionClass, Collection::class)) {
    throw new \LogicException("{$collectionClass} must extend \\Illuminate\\Support\\Collection");
}
// safe to reference in cast string: AsCollection::class . ':' . $collectionClass

Type guard

function isValidCollectionClass(string $class): bool
{
    return class_exists($class) && is_subclass_of($class, \Illuminate\Support\Collection::class);
}

Prevention

When it happens

Trigger: Declaring a cast as AsCollection::class . ':' . SomeClass::class where SomeClass does not extend Illuminate\Support\Collection (e.g. a plain data object, a DTO, or a generic iterator). Also triggered by passing a fully-qualified class string that is misspelled or points to a non-Collection class. Reading the cast attribute (the get() method) runs the is_a() check.

Common situations: Using a custom collection class that was renamed or moved between Laravel versions; referencing a class whose namespace changed after an upgrade; passing an enum or interface name instead of a concrete Collection subclass; copy-pasting a cast from another project whose collection class does not exist here.

Related errors


AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11). Data as JSON: /api/errors/c49077abbd0a8f2c. Report an issue: GitHub.

Appendix: source

Thrown at src/Illuminate/Database/Eloquent/Casts/AsCollection.php:41

        return new class($arguments) implements CastsAttributes
        {
            public function __construct(protected array $arguments)
            {
                $this->arguments = array_pad(array_values($this->arguments), 2, '');
            }

            public function get($model, $key, $value, $attributes)
            {
                if (! isset($attributes[$key])) {
                    return;
                }

                $data = Json::decode($attributes[$key]);

                $collectionClass = empty($this->arguments[0]) ? Collection::class : $this->arguments[0];

                if (! is_a($collectionClass, Collection::class, true)) {
                    throw new InvalidArgumentException('The provided class must extend ['.Collection::class.'].');
                }

                if (! is_array($data)) {
                    return null;
                }

                $instance = new $collectionClass($data);

                if (! isset($this->arguments[1]) || ! $this->arguments[1]) {
                    return $instance;
                }

                if (is_string($this->arguments[1])) {
                    $this->arguments[1] = Str::parseCallback($this->arguments[1]);
                }

                return is_callable($this->arguments[1])
                    ? $instance->map($this->arguments[1])

View on GitHub (pinned to e0f6eb3518)