laravel/framework · error · ValueError

Value [%s] is not of the expected enum type [%s].

Error message

Value [%s] is not of the expected enum type [%s].

What it means

getStorableEnumValue() is invoked when persisting an enum-cast attribute. It requires the value be an instance of the enum class declared in $casts. If a different enum (or any non-matching UnitEnum) is assigned, a ValueError is thrown because the value cannot be safely stored for that column.

Source

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

    {
        return is_subclass_of($enumClass, BackedEnum::class)
            ? $enumClass::from($value)
            : constant($enumClass.'::'.$value);
    }

    /**
     * Get the storable value from the given enum.
     *
     * @param  string  $expectedEnum
     * @param  \UnitEnum  $value
     * @return string|int
     *
     * @throws \ValueError
     */
    protected function getStorableEnumValue($expectedEnum, $value)
    {
        if (! $value instanceof $expectedEnum) {
            throw new ValueError(sprintf('Value [%s] is not of the expected enum type [%s].', var_export($value, true), $expectedEnum));
        }

        return enum_value($value);
    }

    /**
     * Get an array attribute with the given key and value set.
     *
     * @param  string  $path
     * @param  string  $key
     * @param  mixed  $value
     * @return array
     */
    protected function getArrayAttributeWithValue($path, $key, $value)
    {
        return tap($this->getArrayAttributeByKey($key), function (&$array) use ($path, $value) {
            Arr::set($array, str_replace('->', '.', $path), $value);
        });

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Match the enum class exactly: ensure the assigned value is an instance of the cast-target enum.
  2. Convert via the enum's from()/tryFrom() before assignment: $model->status = AppStatus::from($incoming->value).
  3. Update $casts to the correct enum class if the contract changed.

Example fix

// before
$model->status = OtherStatus::Active; // status cast to AppStatus

// after
$model->status = AppStatus::from(OtherStatus::Active->value);
Defensive patterns

Strategy: type-guard

Validate before calling

$expected = \App\Enums\AppStatus::class;
if (! $value instanceof $expected) {
    $value = $expected::from((string) $value); // or tryFrom with fallback
}
$model->status = $value;

Type guard

function isExpectedEnum(mixed $value, string $enumClass): bool
{
    return $value instanceof $enumClass;
}

Try / catch

try {
    $model->status = $value;
} catch (\ValueError $e) {
    if (str_contains($e->getMessage(), 'is not of the expected enum type')) {
        $model->status = \App\Enums\AppStatus::tryFrom((string) $value) ?? \App\Enums\AppStatus::Default;
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: Assigning $model->status = OtherStatus::Active when 'status' is cast to AppStatus; passing a backed-enum of a different type; assigning a UnitEnum where a BackedEnum is expected and the framework cannot extract a scalar.

Common situations: Two similarly-named enums in the codebase; refactor that changed the enum class but left stale data or callers; receiving enum values from an API/form request that maps to the wrong enum; cross-enum assignments in tests.

Related errors


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