laravel/framework · error · MathException
Unable to cast value to a decimal.
Error message
Unable to cast value to a decimal.
What it means
The 'decimal:N' cast uses brick/math BigDecimal to scale the value. If the stored/assigned value cannot be parsed as a number, BigDecimal throws and Eloquent wraps it as MathException('Unable to cast value to a decimal.').
Source
Thrown at src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php:1541
default => (float) $value,
};
}
/**
* Return a decimal as string.
*
* @param float|string $value
* @param int $decimals
* @return string
*
* @throws \Illuminate\Support\Exceptions\MathException
*/
protected function asDecimal($value, $decimals)
{
try {
return (string) BigDecimal::of((string) $value)->toScale($decimals, RoundingMode::HalfUp);
} catch (BrickMathException $e) {
throw new MathException('Unable to cast value to a decimal.', previous: $e);
}
}
/**
* Return a timestamp as DateTime object with time set to 00:00:00.
*
* @param mixed $value
* @return \Illuminate\Support\Carbon
*/
protected function asDate($value)
{
return $this->asDateTime($value)->startOfDay();
}
/**
* Return a timestamp as DateTime object.
*
* @param mixed $valueView on GitHub (pinned to bd6b5437e6)
Solutions
- Sanitize input to a plain numeric string before assignment: cast/strip symbols and thousands separators.
- Use a normalizer: $value = filter_var($input, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION).
- If the column legitimately holds non-numeric data, change the cast to 'string' or 'json'.
Example fix
// before
$model->price = '$1,234.50'; // cast 'decimal:2' -> throws
// after
$model->price = filter_var('$1,234.50', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); Defensive patterns
Strategy: validation
Validate before calling
if (is_string($value) && ! is_numeric($cleaned = preg_replace(['/[^0-9.\-]/'], '', $value))) {
throw new \InvalidArgumentException('Cannot cast to decimal: ' . $value);
}
$model->price = $cleaned ?? $value; Type guard
function isDecimalSafe(mixed $v): bool
{
return is_numeric($v) || (is_string($v) && is_numeric(preg_replace('/[^0-9.\-]/', '', $v)));
} Try / catch
try {
$model->price = $value;
} catch (\Illuminate\Support\Exceptions\MathException $e) {
if (str_contains($e->getMessage(), 'cast value to a decimal')) {
$model->price = filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
} else {
throw $e;
}
} Prevention
- Normalize currency/price inputs (strip symbols, thousands separators) before assigning.
- Use a Form Request rule (numeric|decimal) on incoming decimal fields.
- Validate CSV/Excel imports against is_numeric before persistence.
When it happens
Trigger: Storing a non-numeric string in a decimal-cast column, e.g. $model->price = 'N/A' with 'price' => 'decimal:2'; importing a CSV where a decimal cell contains currency symbols or whitespace; null coerced to string under unusual drivers.
Common situations: Currency/price fields receiving formatted strings ('$1,234.50'); Excel/CSV import with locale-aware decimals; JSON API sending strings with units; mismatched cast precision vs. column type.
Related errors
- The provided class must extend [{Collection::class}].
- The provided class must extend [{Collection::class}].
- The cast object for the {$attribute} attribute must implemen
- Value [%s] is not of the expected enum type [%s].
- Could not verify the hashed value's configuration.
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/2b1c41e7d954acf6.json.
Report an issue: GitHub.