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
- 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)
- Whitelist the unit against that list before calling roundUnit/ceilUnit/floorUnit when the value comes from external input
- Wrap the call in try/catch (UnknownUnitException) and fall back to a known-safe unit such as 'day' or reject the request
- 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
- Keep the unit list in one shared constant/enum and reuse it in both validation and rounding calls
- Never forward raw request/config strings into roundUnit without a whitelist
- Normalize with Carbon::singularUnit() before comparing so plurals never sneak through as 'valid'
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
- Unsupported unit '$unit'
- Invalid unit for real timestamp add/sub: '$unit'
- Unable to add unit '.var_export($originalArgs, true)
- Invalid serialized value: $value
- $anchorDay must be greater than 0
AI-assisted analysis of briannesbitt/Carbon@b13f05955d (2026-08-17).
Data as JSON: /api/errors/e62e485e851b0dbd.
Report an issue: GitHub.