Skip to content

fix(type): check that UUID values are valid UUIDs - #706

Open
otnc wants to merge 1 commit into
marcj:masterfrom
otnc:fix/type-uuid-validation
Open

otnc wants to merge 1 commit into
marcj:masterfrom
otnc:fix/type-uuid-validation

Conversation

@otnc

@otnc otnc commented Sep 14, 2026

Copy link
Copy Markdown

Summary of changes

The UUID type guard and deserializer only check the length and the positions of the dashes:

`${v}.length === 36 && ${v}[23] === '-' && ${v}[18] === '-' && ${v}[13] === '-' && ${v}[8] === '-'`

So any 36-character string with dashes in those places counts as a UUID, including strings that are not hex at all:

is<UUID>('zzzzzzzz-zzzz-4zzz-8zzz-zzzzzzzzzzzz'); // true
deserialize<UUID>('zzzzzzzz-zzzz-4zzz-8zzz-zzzzzzzzzzzz'); // no error

Both checks now use one pattern that follows RFC 9562:

  • hex digits in the 8-4-4-4-12 layout, case-insensitive
  • version (first character of the third group) 1 to 8
  • variant (first character of the fourth group) 8, 9, a or b
  • or exactly the Nil UUID (00000000-0000-0000-0000-000000000000) or the Max UUID (ffffffff-ffff-ffff-ffff-ffffffffffff)

UUIDs produced by uuid() (v4) still pass, as does any UUID from another RFC 9562 version (v1, v6, v7, …).

Changes:

  • packages/type/src/serializer.ts: a module-level uuidPattern, passed into the generated code with state.setContext, used by both the isUUIDType deserializer decorator and the type guard decorator. The error message stays Not a UUID.
  • packages/type/tests/validation.spec.ts: a UUID test covering is, validate and deserialize with v1, v4, v7, v8, uppercase, Nil and Max as valid, and non-hex, version 0/f, variant 0/c and a near-Nil value as invalid. Against the previous check, the invalid cases pass, so the test fails.

Verification: packages/type runs 48 suites and 1854 tests. The only failures are the same 9 in tests/compiler.spec.ts that also fail on master in my environment (Windows). Every UUID-shaped literal in the repository's sources and tests already satisfies the new pattern.

This is stricter than before, so strings that only had the right length and dashes are now rejected by is<UUID>, validate<UUID> and deserialization.

Relinquishment of Rights

Please mark following checkbox to confirm that you relinquish all rights of your changes:

  • I waive and relinquish all rights regarding this changes (including code, text, and images) to Deepkit UG (limited), Germany. This changes (including code, text, and images) are under MIT license without name attribution, copyright notice, and permission notice requirement.

The UUID type guard and deserializer only checked the length and the dash positions, so any 36-character string with dashes in the right places passed, including ones with non-hex characters. They now match RFC 9562: hex digits, version 1 to 8, the RFC variant, or the Nil and Max UUIDs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant