briannesbitt/Carbon · error · UnitException
Invalid unit for real timestamp add/sub: '$unit'
Error message
Invalid unit for real timestamp add/sub: '$unit'
What it means
addUTCUnit()/subUTCUnit() (formerly addRealUnit) shift the raw UTC timestamp and only accept a fixed switch of units (micro/microsecond, milli/millisecond, second, minute, hour, day, week, month, quarter, year, decade, century, millennium - all as fixed 365-day approximations). An unmatched unit reaches the default branch: with strict mode enabled it throws UnitException; with strict mode off it silently returns the unchanged instance. The throw exists so that silent no-ops become visible when the app opts into strictness.
Source
Thrown at src/Carbon/Traits/Units.php:156
$value *= static::YEARS_PER_DECADE * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
break;
// @call addUTCUnit
case 'century':
$value *= static::YEARS_PER_CENTURY * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
break;
// @call addUTCUnit
case 'millennium':
$value *= static::YEARS_PER_MILLENNIUM * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
break;
default:
if ($this->isLocalStrictModeEnabled()) {
throw new UnitException("Invalid unit for real timestamp add/sub: '$unit'");
}
return $this;
}
$seconds = (int) $value;
$microseconds = (int) round(
(abs((float) $value) - abs($seconds)) * ($value < 0 ? -1 : 1) * static::MICROSECONDS_PER_SECOND,
);
$date = $this->setTimestamp($this->getTimestamp() + $seconds);
return $microseconds ? $date->addUTCUnit('microsecond', $microseconds) : $date;
}
/**
* @deprecated Prefer to use add subUTCUnit() which more accurately defines what it's doing.
*
* Subtract seconds to the instance using timestamp. Positive $value travelsView on GitHub (pinned to b13f05955d)
Solutions
- Use a unit from the accepted switch list (microsecond, millisecond, second, minute, hour, day, week, month, quarter, year, decade, century, millennium; 'micro'/'milli' aliases allowed)
- If the unit is calendar-sensitive (weekday, business days), use addUnit()/add() instead of addUTCUnit()
- Whitelist dynamic units before the call, mapping unknown values to a safe default
- If the old silent no-op behavior is genuinely desired, disable strict mode locally via settings(['strict_mode' => false]) on that instance, or catch UnitException
Example fix
// before
$date->addUTCUnit('businessDay', 2);
// after
$date->addWeekday(2); // or $date->addUnit('day', 2) for plain UTC days Defensive patterns
Strategy: type-guard
Validate before calling
$utcUnits = ['micro','microsecond','milli','millisecond','second','minute','hour','day','week','month','quarter','year','decade','century','millennium'];
if (!in_array(Carbon::singularUnit(strtolower($unit)), $utcUnits, true)
&& !in_array(strtolower($unit), $utcUnits, true)) {
throw new InvalidArgumentException("Unit not supported for UTC arithmetic: $unit");
}
$date->addUTCUnit($unit, $value); Type guard
function isUTCUnit(string $unit): bool
{
return in_array(strtolower($unit), [
'micro','microsecond','milli','millisecond','second','minute','hour',
'day','week','month','quarter','year','decade','century','millennium',
], true);
} Try / catch
use Carbon\Exceptions\UnitException;
try {
$date = $date->addUTCUnit($unit, $value);
} catch (UnitException $e) {
// unknown unit surfaced by strict mode - fix data or fall back
$date = $date->addUnit('day', $value);
} Prevention
- Remember addUTCUnit uses fixed 365-day months/years - prefer addUnit for calendar-aware units
- Do not assume silent-skip behavior: strict mode makes bad units throw, so validate at the boundary
- Keep unit vocabulary in one enum and validate once where input enters the system
When it happens
Trigger: Carbon::now()->addUTCUnit('hourss', 3) typo; ->subUTCUnit('businessDay', 1) with a domain-specific unit; a dynamic unit string from config reaching a UTC add path; enabling strict mode (Carbon 3 strict mode is on by default, or via settings/local strict flag) on code that previously relied on the silent skip; legacy calls to the deprecated addRealUnit() alias with a unit not in the switch.
Common situations: Typo in a unit literal; refactoring calendar-aware addUnit() calls to timestamp-based addUTCUnit() and assuming the unit sets are identical (weekday, for example, has no UTC case); turning strict mode on globally during a cleanup and uncovering previously swallowed units; unit strings built by concatenation.
Related errors
- Unknown unit '$unit'.
- Unable to add unit '.var_export($originalArgs, true)
- Unsupported unit '$unit'
- Method $method does not exist.
- Invalid serialized value: $value
AI-assisted analysis of briannesbitt/Carbon@b13f05955d (2026-08-17).
Data as JSON: /api/errors/0f4a51e13a55bd71.
Report an issue: GitHub.