briannesbitt/Carbon · error · UnknownUnitException

Unknown unit '$unit'.

Error message

Unknown unit '$unit'.

What it means

Thrown by roundUnit()/ceilUnit()/floorUnit() (and the round()/ceil()/floor() wrappers that take a unit) when the requested unit is not in the rounding ranges table. The unit is first singularized and meta-units are normalized (millennium/century/decade to year, quarter to month, millisecond to microsecond, week to day with precision x 7); anything left over - a typo or a non-temporal word - has no range to iterate, so Carbon rejects it with UnknownUnitException. It exists to fail fast instead of silently returning an unrounded date.

Source

Thrown at src/Carbon/Traits/Rounding.php:74

        $ranges = array_merge(static::getRangesByUnit($this->daysInMonth), [
            // @call roundUnit
            'microsecond' => [0, 999999],
        ]);
        $factor = 1;

        if ($normalizedUnit === 'week') {
            $normalizedUnit = 'day';
            $precision *= static::DAYS_PER_WEEK;
        }

        if (isset($metaUnits[$normalizedUnit])) {
            [$factor, $normalizedUnit] = $metaUnits[$normalizedUnit];
        }

        $precision *= $factor;

        if (!isset($ranges[$normalizedUnit])) {
            throw new UnknownUnitException($unit);
        }

        $found = false;
        $fraction = 0;
        $arguments = null;
        $initialValue = null;
        $factor = $this->year < 0 ? -1 : 1;
        $changes = [];
        $minimumInc = null;

        foreach ($ranges as $unit => [$minimum, $maximum]) {
            if ($normalizedUnit === $unit) {
                $arguments = [$this->$unit, $minimum];
                $initialValue = $this->$unit;
                $fraction = $precision - floor($precision);
                $found = true;

                continue;

View on GitHub (pinned to b13f05955d)

Solutions

  1. Fix the unit string to a supported one: millennium, century, decade, quarter, year, month, week, day, hour, minute, second, millisecond, microsecond (singular; some plurals are normalized via singularUnit, but verify with the exact string you pass)
  2. Whitelist the unit against that list before calling roundUnit/ceilUnit/floorUnit when the value comes from external input
  3. Wrap the call in try/catch (UnknownUnitException) and fall back to a known-safe unit such as 'day' or reject the request
  4. Check the exception message: it echoes the original $unit before normalization, so the typo is visible verbatim

Example fix

// before
$date->roundUnit($request->query('unit'));

// after
$allowed = ['millennium','century','decade','quarter','year','month','week','day','hour','minute','second','millisecond','microsecond'];
$unit = strtolower((string) $request->query('unit'));
$date->roundUnit(in_array($unit, $allowed, true) ? $unit : 'day');
Defensive patterns

Strategy: type-guard

Validate before calling

$unit = Carbon::singularUnit(strtolower((string) $inputUnit));
if (!in_array($unit, ['millennium','century','decade','quarter','year','month','week','day','hour','minute','second','millisecond','microsecond'], true)) {
    throw new InvalidArgumentException("Unsupported rounding unit: $inputUnit");
}
$date->roundUnit($unit, $precision);

Type guard

function isRoundableUnit(string $unit): bool
{
    return in_array(Carbon::singularUnit(strtolower($unit)), [
        'millennium','century','decade','quarter','year','month','week','day',
        'hour','minute','second','millisecond','microsecond',
    ], true);
}

Try / catch

use Carbon\Exceptions\UnknownUnitException;

try {
    $date = $date->roundUnit($unit);
} catch (UnknownUnitException $e) {
    $date = $date->roundUnit('day'); // or reject the input with 422
}

Prevention

When it happens

Trigger: Calling Carbon::parse('2024-01-15 10:23')->roundUnit('miutes') (typo); ->roundUnit('fortnight'); ->floorUnit('') with an empty string; ->ceilUnit('timezone') with a property name instead of a unit; passing a unit string taken straight from an HTTP request, config value, or DB column without whitelisting it.

Common situations: Unit names assembled dynamically from user input or i18n config; renaming a unit in one place ('mins') while roundUnit expects 'minute'; copying a unit that works with diffForHumans or CarbonInterval (e.g. a plural or an alias) into a rounding call where it is not supported; upgrading Carbon major versions where accepted alias lists changed.

Related errors


AI-assisted analysis of briannesbitt/Carbon@b13f05955d (2026-08-17). Data as JSON: /api/errors/e62e485e851b0dbd. Report an issue: GitHub.