ramsey/uuid · error · InvalidArgumentException
Length must be an even number
Error message
Length must be an even number
What it means
CombGenerator::generate() requires an even byte length (InvalidArgumentException otherwise) because it assembles the value from hexadecimal pairs - the timestamp is produced as hex and padded to TIMESTAMP_BYTES * 2 characters before being packed back to bytes.
Source
Thrown at src/Generator/CombGenerator.php:83
private NumberConverterInterface $numberConverter
) {
}
/**
* @throws InvalidArgumentException if $length is not a positive integer greater than or equal to CombGenerator::TIMESTAMP_BYTES
*
* @inheritDoc
*/
public function generate(int $length): string
{
if ($length < self::TIMESTAMP_BYTES) {
throw new InvalidArgumentException(
'Length must be a positive integer greater than or equal to ' . self::TIMESTAMP_BYTES
);
}
if ($length % 2 !== 0) {
throw new InvalidArgumentException('Length must be an even number');
}
$hash = '';
/** @phpstan-ignore greater.alwaysTrue (TIMESTAMP_BYTES constant could change in child classes) */
if (self::TIMESTAMP_BYTES > 0 && $length > self::TIMESTAMP_BYTES) {
$hash = $this->generator->generate($length - self::TIMESTAMP_BYTES);
}
$lsbTime = str_pad(
$this->numberConverter->toHex($this->timestamp()),
self::TIMESTAMP_BYTES * 2,
'0',
STR_PAD_LEFT,
);
return (string) hex2bin(str_pad(bin2hex($hash), $length - self::TIMESTAMP_BYTES, '0') . $lsbTime);
}View on GitHub (pinned to da5b521600)
Solutions
- Round the length: $length = (int) ceil($length / 2) * 2; and keep it >= 6.
- Validate size configuration at boot so odd lengths never reach generate().
- Replace COMB usage with Uuid::uuid7() to drop the constraint entirely.
Example fix
// before $bytes = $combGenerator->generate(15); // odd -> InvalidArgumentException // after $length = max(6, (int) ceil(15 / 2) * 2); // 16 $bytes = $combGenerator->generate($length);
Defensive patterns
Strategy: validation
Validate before calling
$length = max(6, (int) ceil($requestedLength / 2) * 2); // even and >= 6 $bytes = $combGenerator->generate($length);
Type guard
function isValidCombLength(int $length): bool
{
return $length >= 6 && $length % 2 === 0;
} Prevention
- Round computed lengths to the next even number before calling generate().
- Keep length constants (not formulas) for ID sizes in config.
- Test boundary values (5, 6, 7, 15, 16) against your length helper.
- Adopt UUIDv7 to eliminate COMB length rules entirely.
When it happens
Trigger: $combGenerator->generate(15) or any odd length; computing length dynamically (e.g. strlen-derived) and passing an odd result.
Common situations: Configurable ID sizes computed from user input or column sizes; porting token code that assumed odd sizes were fine; combining this check's sibling error (length < 6) during refactors.
Related errors
- Length must be a positive integer greater than or equal to 6
- Could not find a suitable builder for the provided codec and
- Expected version 1 (time-based) UUID
- $bytes string should contain 16 characters.
- Attempting to decode a non-time-based UUID using OrderedTime
AI-assisted analysis of ramsey/uuid@da5b521600 (2026-08-21).
Data as JSON: /api/errors/873222b5fe89052a.
Report an issue: GitHub.