laravel/framework · error · InvalidArgumentException

The cast object for the {$attribute} attribute must implemen

Error message

The cast object for the {$attribute} attribute must implement Stringable.

What it means

mergeCasts()/ensureCastsAreStringValues() accepts object-based casts but they must implement Stringable so the framework can serialize them into the casts array (which holds string cast definitions). Non-Stringable objects cannot be expressed as a cast string.

Source

Thrown at src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php:821

    /**
     * Ensure that the given casts are strings.
     *
     * @param  array  $casts
     * @return array
     *
     * @throws \InvalidArgumentException
     */
    protected function ensureCastsAreStringValues($casts)
    {
        foreach ($casts as $attribute => $cast) {
            $casts[$attribute] = match (true) {
                is_object($cast) => value(function () use ($cast, $attribute) {
                    if ($cast instanceof Stringable) {
                        return (string) $cast;
                    }

                    throw new InvalidArgumentException(
                        "The cast object for the {$attribute} attribute must implement Stringable."
                    );
                }),
                is_array($cast) => value(function () use ($cast) {
                    if (count($cast) === 1) {
                        return $cast[0];
                    }

                    [$cast, $arguments] = [array_shift($cast), $cast];

                    return $cast.':'.implode(',', $arguments);
                }),
                default => $cast,
            };
        }

        return $casts;
    }

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Implement the Stringable (or simply __toString()) interface on the cast object so it can render to a cast string.
  2. Pass the class name string (e.g. MyCaster::class) instead of an instance when registering the cast.
  3. Implement Castable on the class and use its ::class string in $casts.

Example fix

// before
$model->mergeCasts(['settings' => new PlainObject]);

// after
class SettingsCast implements \Illuminate\Contracts\Database\Eloquent\CastsAttributes, \Stringable
{
    public function __toString(): string { return SettingsCast::class; }
}
$model->mergeCasts(['settings' => new SettingsCast]);
Defensive patterns

Strategy: type-guard

Validate before calling

foreach ($castsToMerge as $attr => $cast) {
    if (is_object($cast) && ! ($cast instanceof \Stringable)) {
        throw new \InvalidArgumentException("{$attr} cast object must implement Stringable");
    }
}
$model->mergeCasts($castsToMerge);

Type guard

function castObjectIsValid(mixed $cast): bool
{
    return ! is_object($cast) || $cast instanceof \Stringable;
}

Try / catch

try {
    $model->mergeCasts($casts);
} catch (\InvalidArgumentException $e) {
    if (str_contains($e->getMessage(), 'must implement Stringable')) {
        report('Non-Stringable cast object passed');
    }
    throw $e;
}

Prevention

When it happens

Trigger: Calling $model->mergeCasts(['payload' => $someObject]) or assigning $casts[] = $someObject at runtime where $someObject is a plain stdClass or a class without __toString(). Also from passing a custom caster object that was meant to be a class string.

Common situations: Confusing a CastsAttributes instance (which should be passed as a class string or via ::class) with an object; passing a value object instead of a castable class string; third-party package that returns plain objects as casts.

Related errors


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