briannesbitt/Carbon · error · UnitException

Unable to add unit '.var_export($originalArgs, true)

Error message

Unable to add unit '.var_export($originalArgs, true)

What it means

addUnit() (also reachable via add()/subUnit()/subtract()) converts the unit and value to a CarbonInterval or falls back to DateTime::modify inside rawAddUnit(); if that pipeline throws UnsupportedUnitException, DateMalformedStringException or InvalidFormatException, the date result is null and Carbon rethrows UnitException with var_export() of the original arguments and the root cause chained as previous. It is the catch-all 'the unit/value pair could not be applied' error, so the real reason is in getPrevious().

Source

Thrown at src/Carbon/Traits/Units.php:394

            $date = self::rawAddUnit($date, $unit, $value);

            if ($date !== null) {
                if (isset($timeString)) {
                    $date = $date->setTimeFromTimeString($timeString);
                } elseif (isset($canOverflow, $day) && $canOverflow && $day !== $date->day) {
                    $date = $date->modify('last day of previous month');
                }

                if ($anchorDay !== null) {
                    $date = $date->setAnchorDay($anchorDay);
                }
            }
        } catch (DateMalformedStringException|InvalidFormatException|UnsupportedUnitException $exception) {
            $date = null;
            $previousException = $exception;
        }

        return $date ?? throw new UnitException(
            'Unable to add unit '.var_export($originalArgs, true),
            previous: $previousException,
        );
    }

    /**
     * Subtract given units to the current instance.
     */
    public function subUnit(
        Unit|string $unit,
        $value = 1,
        OverflowMode|bool|null $overflow = null,
        ?int $anchorDay = null,
    ): static {
        return $this->addUnit($unit, -$value, $overflow, $anchorDay);
    }

    /**

View on GitHub (pinned to b13f05955d)

Solutions

  1. Inspect getPrevious() on the caught UnitException: UnsupportedUnitException means the unit is unrecognized, DateMalformedStringException/InvalidFormatException points at the value/string
  2. Fix or whitelist the unit against the Unit enum / supported list before calling addUnit
  3. Clamp or bound computed values (reject |value| beyond a sane range) before passing them in
  4. Catch UnitException at the boundary and map it to a 422/validation error instead of a 500

Example fix

// before
$date->addUnit($unitFromRequest, $amount);

// after
try {
    $date->addUnit($unitFromRequest, $amount);
} catch (UnitException $e) {
    $reason = $e->getPrevious() ? get_class($e->getPrevious()) : 'unknown';
    throw new InvalidArgumentException("Cannot apply $amount $unitFromRequest ($reason)", 0, $e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

$value = (float) $amount;
if (!is_finite($value) || abs($value) > 1e9) {
    throw new InvalidArgumentException("Refusing to add unrealistic amount: $amount");
}
if (!$unit instanceof Unit && !in_array((string) $unit, array_map(fn (Unit $u) => $u->value, Unit::cases()), true)) {
    throw new InvalidArgumentException("Unknown unit: $unit");
}

Type guard

function isKnownUnit(mixed $unit): bool
{
    if ($unit instanceof Unit) {
        return true;
    }
    static $names;
    $names ??= array_map(fn (Unit $u) => $u->value, Unit::cases());

    return in_array(Carbon::singularUnit(strtolower((string) $unit)), $names, true);
}

Try / catch

use Carbon\Exceptions\UnitException;

try {
    $result = $date->addUnit($unit, $value);
} catch (UnitException $e) {
    $root = $e->getPrevious(); // UnsupportedUnitException | InvalidFormatException | DateMalformedStringException
    logger()->warning('addUnit failed', ['unit' => $unit, 'value' => $value, 'root' => $root]);
    throw new ValidationException('Unsupported date arithmetic');
}

Prevention

When it happens

Trigger: $date->addUnit('fortnight', 3) where neither CarbonInterval::fromString('3 fortnight') nor modify('3 fortnight') parses; $date->add(5, 'dayz') typo; a string value like 'NaN' or INF surviving is_numeric guards in float form and producing a malformed modify string; huge computed values (e.g. 1e17 years) that overflow PHP's date range during the fallback modify.

Common situations: Unit typos in migrated code; unit enums/strings from external input passed unvalidated; arithmetic on user-supplied quantities producing astronomically large values; Carbon major upgrades where a previously tolerated unit string is no longer parsed by the interval parser.

Related errors


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