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 travels

View on GitHub (pinned to b13f05955d)

Solutions

  1. 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)
  2. If the unit is calendar-sensitive (weekday, business days), use addUnit()/add() instead of addUTCUnit()
  3. Whitelist dynamic units before the call, mapping unknown values to a safe default
  4. 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

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


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