{"id":"d3b4a56291c6da48","repo":"laravel/framework","slug":"the-provided-class-must-extend-collection-class","errorCode":null,"errorMessage":"The provided class must extend [{Collection::class}].","messagePattern":"The provided class must extend \\[(.+?)\\]\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Illuminate/Database/Eloquent/Casts/AsCollection.php","lineNumber":41,"sourceCode":"        return new class($arguments) implements CastsAttributes\n        {\n            public function __construct(protected array $arguments)\n            {\n                $this->arguments = array_pad(array_values($this->arguments), 2, '');\n            }\n\n            public function get($model, $key, $value, $attributes)\n            {\n                if (! isset($attributes[$key])) {\n                    return;\n                }\n\n                $data = Json::decode($attributes[$key]);\n\n                $collectionClass = empty($this->arguments[0]) ? Collection::class : $this->arguments[0];\n\n                if (! is_a($collectionClass, Collection::class, true)) {\n                    throw new InvalidArgumentException('The provided class must extend ['.Collection::class.'].');\n                }\n\n                if (! is_array($data)) {\n                    return null;\n                }\n\n                $instance = new $collectionClass($data);\n\n                if (! isset($this->arguments[1]) || ! $this->arguments[1]) {\n                    return $instance;\n                }\n\n                if (is_string($this->arguments[1])) {\n                    $this->arguments[1] = Str::parseCallback($this->arguments[1]);\n                }\n\n                return is_callable($this->arguments[1])\n                    ? $instance->map($this->arguments[1])","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/laravel/framework/blob/bd6b5437e6ad87bb49f9b426724f07a9f64e9683/src/Illuminate/Database/Eloquent/Casts/AsCollection.php#L23-L59","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the target class extend Illuminate\\Support\\Collection (e.g. class MyCollection extends \\Illuminate\\Support\\Collection).","If you do not need a custom collection type, drop the first argument: use AsCollection::class alone or AsCollection::of(Item::class).","Verify with is_a($class, \\Illuminate\\Support\\Collection::class, true) at boot before assigning the cast."],"exampleFix":"// before\nprotected $casts = [\n    'tags' => AsCollection::class.':'.TagBag::class, // TagBag does not extend Collection\n];\n\n// after\nprotected $casts = [\n    'tags' => AsCollection::class, // default Illuminate\\Support\\Collection\n];\n// OR make TagBag extend Collection:\nclass TagBag extends \\Illuminate\\Support\\Collection {}","handlingStrategy":"validation","validationCode":"use Illuminate\\Support\\Collection;\n$cls = \\App\\Support\\MyCollection::class;\nif (! is_a($cls, Collection::class, true)) {\n    throw new \\LogicException(\"{$cls} must extend \".Collection::class);\n}\n// only then use it in AsCollection::using($cls)","typeGuard":"function isValidCollectionClass(string $class): bool\n{\n    return is_a($class, \\Illuminate\\Support\\Collection::class, true);\n}","tryCatchPattern":"try {\n    return $model->meta;\n} catch (\\InvalidArgumentException $e) {\n    if (str_contains($e->getMessage(), 'must extend [')) {\n        \\Log::error('Bad AsCollection class on '.get_class($model), ['msg' => $e->getMessage()]);\n    }\n    throw $e;\n}","preventionTips":["Always extend Illuminate\\Support\\Collection when creating custom collection types.","Use AsCollection::of(Item::class) when you only need item mapping, not a custom collection class.","Add a boot-time assertion in tests that checks every casted class string in $casts."],"tags":["eloquent","cast","collection","type-error"],"analyzedSha":"bd6b5437e6ad87bb49f9b426724f07a9f64e9683","analyzedAt":"2026-08-06T00:28:32.783Z","schemaVersion":2}