laravel/framework · error · InvalidArgumentException

The provided class must extend [Illuminate\Support\Collectio

Error message

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

What it means

Thrown by the AsEncryptedCollection cast (the encrypted variant of AsCollection) when the first argument does not extend Illuminate\Support\Collection. The anonymous cast class validates the collection class with is_a(..., true) before decrypting and wrapping the JSON payload, so a non-Collection class is rejected before any decryption work happens.

Source

Thrown at src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php:36

     * @return \Illuminate\Contracts\Database\Eloquent\CastsAttributes<\Illuminate\Support\Collection<array-key, mixed>, iterable>
     *
     * @throws \InvalidArgumentException
     */
    public static function castUsing(array $arguments)
    {
        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)
            {
                $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 (! isset($attributes[$key])) {
                    return null;
                }

                $instance = new $collectionClass(Json::decode(Crypt::decryptString($attributes[$key])));

                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)

Solutions

  1. Confirm the first argument class extends Illuminate\Support\Collection with is_subclass_of().
  2. Correct the fully-qualified class name / import in the cast string.
  3. Use AsEncryptedCollection::class with no custom class argument to fall back to the base Collection.
  4. Extend Collection in your custom class if you need specialized behavior.

Example fix

// before
protected $casts = [
    'secret_list' => AsEncryptedCollection::class . ':' . App\DTO\SecretList::class,
];

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

protected $casts = [
    'secret_list' => AsEncryptedCollection::class . ':' . App\DTO\SecretList::class,
];
Defensive patterns

Strategy: validation

Validate before calling

use Illuminate\Support\Collection;

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

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 AsEncryptedCollection::class . ':' . SomeClass::class where SomeClass is not a Collection subclass. Triggered when reading the encrypted attribute (get()), which runs the is_a() check before decrypting via Crypt::decryptString and constructing the collection.

Common situations: Switching an attribute from AsCollection to AsEncryptedCollection but keeping a custom class that was never made a Collection subclass; referencing a class that was deleted or renamed; using a third-party collection wrapper that does not extend the base Collection.

Related errors


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