ramsey/uuid · error · TimeSourceException

The generated time of '%s' is larger than expected

Error message

The generated time of '%s' is larger than expected

What it means

DefaultTimeGenerator converts the current time into 60-bit UUID time and pads it to exactly 16 hex characters; if the converted value exceeds that width, str_pad cannot shrink it and the generator throws TimeSourceException - the wall clock (or time provider) produced a time too large for a version 1 UUID to encode.

Source

Thrown at src/Generator/DefaultTimeGenerator.php:82

            try {
                // This does not use "stable storage"; see RFC 9562, section 6.3.
                $clockSeq = random_int(0, 0x3fff);
            } catch (Throwable $exception) {
                throw new RandomSourceException($exception->getMessage(), (int) $exception->getCode(), $exception);
            }
        }

        $time = $this->timeProvider->getTime();

        $uuidTime = $this->timeConverter->calculateTime(
            $time->getSeconds()->toString(),
            $time->getMicroseconds()->toString()
        );

        $timeHex = str_pad($uuidTime->toString(), 16, '0', STR_PAD_LEFT);

        if (strlen($timeHex) !== 16) {
            throw new TimeSourceException(sprintf('The generated time of \'%s\' is larger than expected', $timeHex));
        }

        $timeBytes = (string) hex2bin($timeHex);

        return $timeBytes[4] . $timeBytes[5] . $timeBytes[6] . $timeBytes[7]
            . $timeBytes[2] . $timeBytes[3] . $timeBytes[0] . $timeBytes[1]
            . pack('n*', $clockSeq) . $node;
    }

    /**
     * Uses the node provider given when constructing this instance to get the node ID (usually a MAC address)
     *
     * @param int | string | null $node A node value that may be used to override the node provider
     *
     * @return string 6-byte binary string representation of the node
     *
     * @throws InvalidArgumentException
     */

View on GitHub (pinned to da5b521600)

Solutions

  1. Fix the clock: verify date/NTP inside the container or host (date -u).
  2. Audit custom TimeProvider implementations - getTime() must return seconds plus separate microseconds.
  3. In tests, keep FixedTimeProvider timestamps within a sane epoch range.
  4. Catch TimeSourceException at generation boundaries and fail loudly rather than persisting anything derived from a bad clock.

Example fix

// before (custom provider passing microseconds as seconds)
return new Time((int) ($now * 1000000), 0); // TimeSourceException: > 16 hex chars

// after
[$usec, $sec] = explode(' ', microtime());
return new Time((int) $sec, (int) ($usec * 1000000)); // seconds + microseconds
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check the wall clock before relying on v1 generation.
$now = time();
if ($now < 1000000000 || $now > 2000000000) { // ~2001..2033 window
    throw new RuntimeException('system clock is not sane; refusing to generate v1 UUIDs');
}

Try / catch

try {
    $uuid = Uuid::uuid1();
} catch (\Ramsey\Uuid\Exception\TimeSourceException $e) {
    // clock/time-provider produced an unrepresentable time
    $fallback = Uuid::uuid4(); // non-time identifier that always works
    // alert ops: clock skew or provider unit bug
}

Prevention

When it happens

Trigger: A system/container clock set far beyond the v1 range (post-year-5236 territory), or - far more commonly - a custom TimeProviderInterface implementation returning wrong units, e.g. microseconds passed where seconds are expected, inflating the value ~1e6x.

Common situations: Broken VM/container clocks or NTP misconfiguration; hand-rolled time providers with unit bugs; test doubles / FixedTimeProvider seeded with huge values; embedded boards with unset clocks defaulting to far-future epochs.

Related errors


AI-assisted analysis of ramsey/uuid@da5b521600 (2026-08-21). Data as JSON: /api/errors/6a6afa1fa2476a8c. Report an issue: GitHub.