ramsey/uuid · error · InvalidArgumentException

The byte string received does not contain a valid RFC 9562 (

Error message

The byte string received does not contain a valid RFC 9562 (formerly RFC 4122) version

What it means

Rfc4122\Fields (via VersionTrait::isCorrectVersion) requires the version nibble — first hex character of the 3rd group — to be 1 through 8 for non-nil/non-max UUIDs. Version 0 or 9-f means the value does not follow RFC 9562's version field, so the constructor throws InvalidArgumentException; through the standard parse path this message is carried by a wrapping UnableToBuildUuidException.

Source

Thrown at src/Rfc4122/Fields.php:70

     * @throws InvalidArgumentException if the byte string does not represent an RFC 9562 (formerly RFC 4122) UUID
     * @throws InvalidArgumentException if the byte string does not contain a valid version
     */
    public function __construct(private string $bytes)
    {
        if (strlen($this->bytes) !== 16) {
            throw new InvalidArgumentException(
                'The byte string must be 16 bytes long; ' . 'received ' . strlen($this->bytes) . ' bytes',
            );
        }

        if (!$this->isCorrectVariant()) {
            throw new InvalidArgumentException(
                'The byte string received does not conform to the RFC 9562 (formerly RFC 4122) variant',
            );
        }

        if (!$this->isCorrectVersion()) {
            throw new InvalidArgumentException(
                'The byte string received does not contain a valid RFC 9562 (formerly RFC 4122) version',
            );
        }
    }

    /**
     * @pure
     */
    public function getBytes(): string
    {
        return $this->bytes;
    }

    public function getClockSeq(): Hexadecimal
    {
        if ($this->isMax()) {
            $clockSeq = 0xffff;
        } elseif ($this->isNil()) {

View on GitHub (pinned to da5b521600)

Solutions

  1. Pre-check the version nibble: hex char at index 12 must be 1-8 (or the value is all-zero/all-f)
  2. Catch UnableToBuildUuidException where untrusted UUID strings enter the system and reject with a domain-specific error
  3. For deliberately arbitrary 128-bit values, use Ulid or keep them as Hexadecimal instead of Uuid

Example fix

// before
$uuid = \Ramsey\Uuid\Uuid::fromString($id); // version nibble invalid

// after
$hex = strtolower(preg_replace('/[^0-9a-f]/i', '', $id));
$version = hexdec($hex[12] ?? '0');
$special = $hex === str_repeat('0', 32) || $hex === str_repeat('f', 32);
if (!$special && ($version < 1 || $version > 8)) {
    throw new InvalidArgumentException('Not an RFC 9562 version UUID');
}
$uuid = \Ramsey\Uuid\Uuid::fromString($id);
Defensive patterns

Strategy: validation

Validate before calling

$hex = strtolower(preg_replace('/^urn:uuid:|[^0-9a-f]/i', '', $candidate));
$version = hexdec($hex[12] ?? '0');
$special = $hex === str_repeat('0', 32) || $hex === str_repeat('f', 32);
if (!$special && ($version < 1 || $version > 8)) {
    throw new InvalidArgumentException('Invalid UUID version nibble');
}
$uuid = \Ramsey\Uuid\Uuid::fromString($candidate);

Type guard

function hasValidRfc4122Version(string $uuid): bool
{
    $hex = strtolower(preg_replace('/^urn:uuid:|[^0-9a-f]/i', '', $uuid));
    if (strlen($hex) !== 32) {
        return false;
    }
    if ($hex === str_repeat('0', 32) || $hex === str_repeat('f', 32)) {
        return true; // nil / max
    }
    $v = hexdec($hex[12]);
    return $v >= 1 && $v <= 8;
}

Try / catch

try {
    $uuid = \Ramsey\Uuid\Uuid::fromString($input);
} catch (\Ramsey\Uuid\Exception\UnableToBuildUuidException $e) {
    if (str_contains($e->getMessage(), 'version')) {
        // version nibble outside 1-8
    }
}

Prevention

When it happens

Trigger: Uuid::fromString('12345678-1234-fabc-9abc-123456789abc') — the 3rd group starts with 'f' (version 15), so parsing throws. Likewise versions 0 and 9-e. Direct Rfc4122\Fields construction or custom builders with such bytes hit the same check. Uuid::isValid() does not catch this because it only validates hex layout.

Common situations: Placeholder/test UUIDs like 'ffffffff-ffff-ffff-...' (non-max misuse); IDs from systems that fill the version field freely (some legacy GUID generators); typo'd constants; bit-shifting bugs in custom encoding code.

Related errors


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