ramsey/uuid · error · InvalidUuidStringException
Invalid UUID string: {encodedUuid}
Error message
Invalid UUID string: {encodedUuid} What it means
StringCodec::getBytes() powers Uuid::fromString() and $codec->decode(): it strips 'urn:uuid:'/'UUID:' prefixes, braces and dashes, re-groups the remainder into five components, and validates the reassembled form with Uuid::isValid(). When validation fails it throws InvalidUuidStringException with the offending input in the message.
Source
Thrown at src/Codec/StringCodec.php:116
}
/**
* Returns a byte string of the UUID
*/
protected function getBytes(string $encodedUuid): string
{
$parsedUuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}', '-'], '', $encodedUuid);
$components = [
substr($parsedUuid, 0, 8),
substr($parsedUuid, 8, 4),
substr($parsedUuid, 12, 4),
substr($parsedUuid, 16, 4),
substr($parsedUuid, 20),
];
if (!Uuid::isValid(implode('-', $components))) {
throw new InvalidUuidStringException('Invalid UUID string: ' . $encodedUuid);
}
return (string) hex2bin($parsedUuid);
}
}
View on GitHub (pinned to da5b521600)
Solutions
- Validate first: if (!Uuid::isValid(trim($value))) { reject } - isValid accepts braces, URN and dashes exactly like fromString.
- Normalize input: trim whitespace/newlines before parsing.
- Reject bad IDs at the API boundary (HTTP 400 / domain error) instead of letting the exception escape.
- Confirm the source wrote a full 32-hex-digit value (column wide enough, no partial reads).
Example fix
// before
$uuid = Uuid::fromString($request->query('id')); // may throw InvalidUuidStringException
// after
$value = trim((string) $request->query('id'));
if (!Uuid::isValid($value)) {
throw new NotFoundHttpException('invalid identifier');
}
$uuid = Uuid::fromString($value); Defensive patterns
Strategy: validation
Validate before calling
$value = trim((string) $input);
if (!\Ramsey\Uuid\Uuid::isValid($value)) {
throw new InvalidArgumentException(sprintf('not a valid UUID string: %s', $value));
}
$uuid = Uuid::fromString($value); Type guard
function isParsableUuidString(mixed $value): bool
{
return is_string($value) && Uuid::isValid(trim($value));
} Try / catch
try {
$uuid = Uuid::fromString($value);
} catch (\Ramsey\Uuid\Exception\InvalidUuidStringException $e) {
// invalid external identifier - respond 404/400 rather than a 500
throw new NotFoundHttpException('unknown identifier');
} Prevention
- Validate with Uuid::isValid() at API boundaries before parsing.
- trim() input from files, CSVs, and config to strip newlines/spaces.
- Ensure char columns are wide enough (36 with dashes) to avoid silent truncation.
- Reject null/scalar coercion early: fromString('') also throws.
When it happens
Trigger: Uuid::fromString() with an empty string, non-hex characters (g-z, punctuation), the wrong number of hex digits after stripping, leading/trailing whitespace or newlines, a ULID or other non-UUID identifier, or a value truncated by copy/paste or a char(32)/char(36) column.
Common situations: Unvalidated user/API input reaching fromString(); CSV/file lines with trailing newline; identifiers truncated by database column width; null coerced to ''; passing a 32-hex COMB string with an odd character.
Related errors
- $bytes string should contain 16 characters.
- 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/daded6c8f5b0445d.
Report an issue: GitHub.