laravel/framework · error · InvalidArgumentException

The provided class must extend [{Collection::class}].

Error message

The provided class must extend [{Collection::class}].

What it means

Thrown by the AsCollection cast when the first argument (the collection class name) does not extend Illuminate\Support\Collection. The cast reads the column as JSON and instantiates the configured class, so it must be a real Collection subclass. The check happens in the cast's get() handler, i.e. whenever the casted attribute is accessed from a persisted model.

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 bd6b5437e6)

Solutions

  1. Make the target class extend Illuminate\Support\Collection (e.g. class MyCollection extends \Illuminate\Support\Collection).
  2. If you do not need a custom collection type, drop the first argument: use AsCollection::class alone or AsCollection::of(Item::class).
  3. Verify with is_a($class, \Illuminate\Support\Collection::class, true) at boot before assigning the cast.

Example fix

// before
protected $casts = [
    'tags' => AsCollection::class.':'.TagBag::class, // TagBag does not extend Collection
];

// after
protected $casts = [
    'tags' => AsCollection::class, // default Illuminate\Support\Collection
];
// OR make TagBag extend Collection:
class TagBag extends \Illuminate\Support\Collection {}
Defensive patterns

Strategy: validation

Validate before calling

use Illuminate\Support\Collection;
$cls = \App\Support\MyCollection::class;
if (! is_a($cls, Collection::class, true)) {
    throw new \LogicException("{$cls} must extend ".Collection::class);
}
// only then use it in AsCollection::using($cls)

Type guard

function isValidCollectionClass(string $class): bool
{
    return is_a($class, \Illuminate\Support\Collection::class, true);
}

Try / catch

try {
    return $model->meta;
} catch (\InvalidArgumentException $e) {
    if (str_contains($e->getMessage(), 'must extend [')) {
        \Log::error('Bad AsCollection class on '.get_class($model), ['msg' => $e->getMessage()]);
    }
    throw $e;
}

Prevention

When it happens

Trigger: Declaring a cast like 'meta' => AsCollection::class.':'.SomeClass::class (or AsCollection::using(SomeClass::class, ...)) where SomeClass is a plain array/object wrapper or a custom class that does not extend Illuminate\Support\Collection. The exception fires on the first read of $model->meta after the row is hydrated from the database.

Common situations: Pointing the cast at a domain DTO or a generic Illuminate\Support\HigherOrderCollectionProxy by mistake; refactoring a custom collection but forgetting to extend the base Collection class; copy-pasting AsCollection::using from a doc sample that uses an arbitrary class string.

Related errors


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