laravel/framework · error · MathException

Unable to cast value to a decimal.

Error message

Unable to cast value to a decimal.

What it means

Thrown as MathException (wrapping Brick\Math\Exception) by asDecimal() when BigDecimal::of() cannot interpret the value as a number, or when scaling fails. The decimal cast converts the value through Brick Math; any parsing error (non-numeric string, malformed input) is re-thrown as MathException with 'Unable to cast value to a decimal.'

Solutions

  1. Sanitize the input to a plain numeric string before assignment (strip currency symbols, thousands separators).
  2. Validate the value is numeric before saving (e.g. is_numeric($value)).
  3. If the column can hold non-numeric data, remove the 'decimal' cast or store it as a string cast.
  4. Normalize locale decimals (str_replace(',', '.', $value)) before casting.

Example fix

// before
protected $casts = ['price' => 'decimal:2'];
$product->price = '$1,234.50'; // MathException

// after
$product->price = (string) Number::format(1234.50); // or
$product->price = '1234.50';
Defensive patterns

Strategy: validation

Validate before calling

if (! is_numeric($value) && $value !== null) {
    throw new \UnexpectedValueException('Decimal cast expects numeric input, got: ' . get_debug_type($value));
}
$model->price = $value;

Type guard

function isCastableToDecimal(mixed $value): bool
{
    return $value === null || is_numeric($value) || (is_string($value) && is_numeric($value));
}

Try / catch

try {
    $model->price = $value;
} catch (\Illuminate\Support\Exceptions\MathException $e) {
    report($e);
    $model->price = '0.00';
}

Prevention

When it happens

Trigger: Casting an attribute as 'decimal:N' and assigning a non-numeric value (e.g. 'abc', an empty string, or null-like garbage), or a value BigDecimal cannot coerce. Triggered on read/write when the decimal cast runs asDecimal().

Common situations: Importing data with stray non-numeric tokens ('$1,234.50', 'N/A', ''); user input not validated before model assignment; a column previously stored as a free-text string now cast as decimal; locale-specific decimal separators (comma) on a system expecting dots.

Related errors


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

Appendix: 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  $value

View on GitHub (pinned to e0f6eb3518)