ramsey/uuid · error · InvalidArgumentException
Expected version 1 (time-based) UUID
Error message
Expected version 1 (time-based) UUID
What it means
OrderedTimeCodec::encodeBinary() rearranges the timestamp bytes of a UUID so v1 UUIDs sort naturally in database indexes; it accepts only version 1 (time-based) RFC 4122 UUIDs. If the fields object is not a Rfc4122FieldsInterface or the version nibble is not 1 (Uuid::UUID_TYPE_TIME), it throws InvalidArgumentException. You hit it by asking a non-v1 UUID carrying this codec for its bytes (getBytes() delegates to encodeBinary()).
Source
Thrown at src/Codec/OrderedTimeCodec.php:59
*
* @immutable
*/
class OrderedTimeCodec extends StringCodec
{
/**
* Returns a binary string representation of a UUID, with the timestamp fields rearranged for optimized storage
*
* @return non-empty-string
*/
public function encodeBinary(UuidInterface $uuid): string
{
if (
/** @phpstan-ignore possiblyImpure.methodCall */
!($uuid->getFields() instanceof Rfc4122FieldsInterface)
/** @phpstan-ignore possiblyImpure.methodCall */
|| $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME
) {
throw new InvalidArgumentException('Expected version 1 (time-based) UUID');
}
/** @phpstan-ignore possiblyImpure.methodCall */
$bytes = $uuid->getFields()->getBytes();
return $bytes[6] . $bytes[7] . $bytes[4] . $bytes[5]
. $bytes[0] . $bytes[1] . $bytes[2] . $bytes[3]
. substr($bytes, 8);
}
/**
* Returns a UuidInterface derived from an ordered-time binary string representation
*
* @throws InvalidArgumentException if $bytes is an invalid length
*
* @inheritDoc
*/
public function decodeBytes(string $bytes): UuidInterfaceView on GitHub (pinned to da5b521600)
Solutions
- Use OrderedTimeCodec only with version 1 UUIDs (Uuid::uuid1()); leave the default codec (or StringCodec) on factories that produce other versions.
- Keep two factory/codec contexts: one OrderedTimeCodec factory for v1, one default factory for everything else.
- For time-ordered non-v1 identifiers prefer UUIDv7 (Uuid::uuid7()) or a COMB with TimestampFirstCombCodec instead of ordered-time v1.
Example fix
// before $factory->setCodec(new OrderedTimeCodec($factory->getUuidBuilder())); $bytes = $factory->uuid4()->getBytes(); // InvalidArgumentException // after $factory->setCodec(new OrderedTimeCodec($factory->getUuidBuilder())); $bytes = $factory->uuid1()->getBytes(); // 16 ordered-time bytes
Defensive patterns
Strategy: type-guard
Validate before calling
// Only encode time-based UUIDs through the ordered-time codec.
$fields = $uuid->getFields();
if ($fields instanceof \Ramsey\Uuid\Rfc4122\FieldsInterface && $fields->getVersion() === Uuid::UUID_TYPE_TIME) {
$orderedBytes = $orderedCodec->encodeBinary($uuid);
} Type guard
/** @psalm-assert-if-true \Ramsey\Uuid\Rfc4122\UuidV1 $uuid */
function isUuidV1(UuidInterface $uuid): bool
{
return $uuid instanceof \Ramsey\Uuid\Rfc4122\UuidV1;
} Try / catch
try {
$bytes = $uuid->getBytes();
} catch (\Ramsey\Uuid\Exception\InvalidArgumentException $e) {
// Non-v1 UUID reached the ordered-time codec; fall back to standard bytes.
$bytes = $uuid->getFields()->getBytes();
} Prevention
- Scope OrderedTimeCodec to a dedicated v1-only factory; keep the default codec elsewhere.
- Type-hint factories and variables as UuidV1 where ordered-time encoding is required.
- Prefer UUIDv7 for time-ordered keys - it needs no special codec.
- Add an architecture test asserting getBytes() is only called on UuidV1 instances in the ordered-time module.
When it happens
Trigger: $factory->setCodec(new OrderedTimeCodec($factory->getUuidBuilder())) set factory-wide, then $factory->uuid4()->getBytes() (or uuid3/uuid5); building a v3/v4/v5 Uuid with an OrderedTimeCodec and serializing it to bytes.
Common situations: Enabling ordered-time storage for index friendliness while still generating v4 random UUIDs through the same factory; mixing COMB/ordered-time strategy with non-time UUID versions; codec switched globally instead of per-version.
Related errors
- $bytes string should contain 16 characters.
- Attempting to decode a non-time-based UUID using OrderedTime
- Not a time-based UUID
- The generated time of '%s' is larger than expected
- Invalid node value
AI-assisted analysis of ramsey/uuid@da5b521600 (2026-08-21).
Data as JSON: /api/errors/1d6dae9615ba33c3.
Report an issue: GitHub.