ramsey/uuid · error · DceSecurityException

Local domain must be a valid DCE Security domain

Error message

Local domain must be a valid DCE Security domain

What it means

DceSecurityGenerator::generate() (the engine behind Uuid::uuid2(), version 2 UUIDs) requires the local domain to be one of the three DCE Security domains: Uuid::DCE_DOMAIN_PERSON (0), Uuid::DCE_DOMAIN_GROUP (1), Uuid::DCE_DOMAIN_ORG (2). Anything else throws DceSecurityException.

Source

Thrown at src/Generator/DceSecurityGenerator.php:69

     * Lower bounds for the clock sequence in DCE Security UUIDs.
     */
    private const CLOCK_SEQ_LOW = 0;

    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');
                }

View on GitHub (pinned to da5b521600)

Solutions

  1. Always pass the constants: Uuid::DCE_DOMAIN_PERSON, Uuid::DCE_DOMAIN_GROUP, or Uuid::DCE_DOMAIN_ORG.
  2. Map domain names to constants before calling: ['person'=>0,'group'=>1,'org'=>2][$name] ?? fail.
  3. Re-check the uuid2() argument order if the value you meant for another slot lands in $localDomain.

Example fix

// before
$uuid = Uuid::uuid2('org'); // string -> DceSecurityException

// after
$uuid = Uuid::uuid2(Uuid::DCE_DOMAIN_ORG, new Integer(42));
Defensive patterns

Strategy: validation

Validate before calling

const DCE_DOMAINS = [
    Uuid::DCE_DOMAIN_PERSON,
    Uuid::DCE_DOMAIN_GROUP,
    Uuid::DCE_DOMAIN_ORG,
];

if (!in_array($localDomain, DCE_DOMAINS, true)) {
    throw new InvalidArgumentException('local domain must be person (0), group (1) or org (2)');
}
$uuid = Uuid::uuid2($localDomain, $identifier);

Type guard

function isDceDomain(int $domain): bool
{
    return in_array($domain, [Uuid::DCE_DOMAIN_PERSON, Uuid::DCE_DOMAIN_GROUP, Uuid::DCE_DOMAIN_ORG], true);
}

Try / catch

try {
    $uuid = Uuid::uuid2($domain, $id);
} catch (\Ramsey\Uuid\Exception\DceSecurityException $e) {
    throw new InvalidConfigurationException('bad DCE domain configuration', $e);
}

Prevention

When it happens

Trigger: Uuid::uuid2(3); Uuid::uuid2('person') (string, not the int constant); passing a clock sequence or identifier in the domain position; casting a domain name from config straight to an int.

Common situations: Positional-argument mix-ups in uuid2($localDomain, $localIdentifier, $node, $clockSeq); storing domains as strings and letting PHP coerce them; inventing custom domains instead of using the constants.

Related errors


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