ramsey/uuid · error · DceSecurityException

Local identifier out of bounds; it must be a value between 0

Error message

Local identifier out of bounds; it must be a value between 0 and 4294967295

What it means

When generating a DCE Security (version 2) UUID, a negative IntegerObject local identifier is rejected with DceSecurityException because the field is an unsigned 32-bit value (0..4294967295). The check runs before any identifier auto-derivation.

Source

Thrown at src/Generator/DceSecurityGenerator.php:73

    public function __construct(
        private NumberConverterInterface $numberConverter,
        private TimeGeneratorInterface $timeGenerator,
        private DceSecurityProviderInterface $dceSecurityProvider,
    ) {
    }

    public function generate(
        int $localDomain,
        ?IntegerObject $localIdentifier = null,
        ?Hexadecimal $node = null,
        ?int $clockSeq = null,
    ): string {
        if (!in_array($localDomain, self::DOMAINS)) {
            throw new DceSecurityException('Local domain must be a valid DCE Security domain');
        }

        if ($localIdentifier && $localIdentifier->isNegative()) {
            throw new DceSecurityException(
                'Local identifier out of bounds; it must be a value between 0 and 4294967295',
            );
        }

        if ($clockSeq > self::CLOCK_SEQ_HIGH || $clockSeq < self::CLOCK_SEQ_LOW) {
            throw new DceSecurityException('Clock sequence out of bounds; it must be a value between 0 and 63');
        }

        switch ($localDomain) {
            case Uuid::DCE_DOMAIN_ORG:
                if ($localIdentifier === null) {
                    throw new DceSecurityException('A local identifier must be provided for the org domain');
                }

                break;
            case Uuid::DCE_DOMAIN_PERSON:
                if ($localIdentifier === null) {
                    $localIdentifier = $this->dceSecurityProvider->getUid();

View on GitHub (pinned to da5b521600)

Solutions

  1. Pass a non-negative IntegerObject (or null to auto-derive uid/gid for person/group domains).
  2. Handle -1 sentinels at the source: treat them as 'unknown' and pass null instead.
  3. Clamp/mask upstream values to the 0..4294967295 range before constructing the Integer.

Example fix

// before
$uuid = Uuid::uuid2(Uuid::DCE_DOMAIN_PERSON, new Integer($uid)); // $uid === -1

// after
$identifier = $uid >= 0 ? new Integer($uid) : null;
$uuid = Uuid::uuid2(Uuid::DCE_DOMAIN_PERSON, $identifier);
Defensive patterns

Strategy: validation

Validate before calling

if ($identifier !== null && ($identifier->isNegative() || $identifier->compareTo(new Integer(4294967295)) > 0)) {
    throw new InvalidArgumentException('local identifier must be 0..4294967295');
}
$uuid = Uuid::uuid2($domain, $identifier);

Type guard

function isValidDceIdentifier(\Ramsey\Uuid\Type\Integer $id): bool
{
    return !$id->isNegative() && $id->compareTo(new \Ramsey\Uuid\Type\Integer(4294967295)) <= 0;
}

Try / catch

try {
    $uuid = Uuid::uuid2($domain, new Integer($uid));
} catch (\Ramsey\Uuid\Exception\DceSecurityException $e) {
    // treat as unknown identity
    $uuid = Uuid::uuid2($domain);
}

Prevention

When it happens

Trigger: Uuid::uuid2(Uuid::DCE_DOMAIN_PERSON, new Integer(-1)); passing a sentinel negative value; a system call that returns -1 on failure and is wrapped unchecked into Integer.

Common situations: Using -1 as an 'unknown id' sentinel; error returns from posix/external systems fed straight into the generator; IDs arriving as signed values from another platform.

Related errors


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