UUID.version / variant

The variant lives in the top bits of the 17th hex digit (the first of the fourth group): 8, 9, a or b means RFC 4122. Only then does the 13th digit (the first of the third group) mean something: it is the version. Any other variant gives version None.

UUID attributesPython 2.5+Live demo
Common call
u.version == 4
Returns
True for a uuid4; version is an int or None
Replaces
Reading str(u)[14] by hand
Watch out
A hand-typed UUID like 12345678-1234-5678-1234-… has variant RESERVED_NCS and version None
u.version · u.variant · uuid.RESERVED_NCS · uuid.RFC_4122 · uuid.RESERVED_MICROSOFT · uuid.RESERVED_FUTURE
→ int | None / str

Demo

Live evaluation
Type a UUID and see what kind it is.
Try:
Inputs
textstra UUID string
Code
import uuid
u = uuid.UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
(u.version, u.variant)
Result
(4, 'specified in RFC 4122')

All zeros is variant RESERVED_NCS and all ones RESERVED_FUTURE, so both have version None. The COM GUID 00000000-0000-0000-c000-000000000046 (IUnknown) is in the Microsoft variant. In the last case the third group starts with 4, yet version is None: the fourth group starts with 1, so the variant is not RFC 4122 and the version digit does not count.

Attributes

AttributeTypeMeaning
versionint | None(int >> 76) & 0xf when the variant is RFC_4122, otherwise None.
variantstrOne of the four constants below, from the top bits of clock_seq_hi_variant.
RESERVED_NCSstr'reserved for NCS compatibility': top bit 0 (fourth group starts with 0 to 7).
RFC_4122str'specified in RFC 4122': top bits 10 (fourth group starts with 8, 9, a or b). Every UUID uuid1/3/4/5 make.
RESERVED_MICROSOFTstr'reserved for Microsoft compatibility': top bits 110 (starts with c or d).
RESERVED_FUTUREstr'reserved for future definition': top bits 111 (starts with e or f).

Common patterns

Accept only random UUIDs
Reject IDs that were not made by uuid4 (for example a uuid1 that leaks a MAC address).
import uuid
u = uuid.UUID(text)
if u.version != 4:
    raise ValueError("expected a version 4 UUID")
Dispatch on the variant
Compare with the module constants, not with the literal strings.
import uuid
if u.variant == uuid.RFC_4122:
    kind = f"RFC 4122 version {u.version}"
else:
    kind = u.variant

Examples

1. A uuid4 is version 4
import uuid uuid.uuid4().version
Returns
4
2. Name-based: 3 and 5
import uuid (uuid.uuid3(uuid.NAMESPACE_DNS, 'x').version, uuid.uuid5(uuid.NAMESPACE_DNS, 'x').version)
Returns
(3, 5)
3. The variant constants are strings
import uuid uuid.RFC_4122
Returns
'specified in RFC 4122'
4. All four
import uuid [uuid.RESERVED_NCS, uuid.RFC_4122, uuid.RESERVED_MICROSOFT, uuid.RESERVED_FUTURE]
Returns
['reserved for NCS compatibility', 'specified in RFC 4122', 'reserved for Microsoft compatibility', 'reserved for future definition']
5. Nil UUID: no version
import uuid print(uuid.UUID(int=0).version)
Returns
None
6. Microsoft variant
import uuid uuid.UUID('00000000-0000-0000-c000-000000000046').variant
Returns
'reserved for Microsoft compatibility'
7. version= sets both
import uuid u = uuid.UUID(int=0, version=4) (u.version, u.variant == uuid.RFC_4122)
Returns
(4, True)

Pitfalls

1. Trusting the version digit alone
A UUID whose third group starts with 4 is not version 4 unless the variant is RFC 4122. version already checks that; a regex on the text usually does not.
str(u)[14]
import uuid
str(uuid.UUID('12345678-1234-4678-1234-567812345678'))[14] == '4'
True
u.version
import uuid
uuid.UUID('12345678-1234-4678-1234-567812345678').version == 4
False
2. Expecting an int for every UUID
version is None outside the RFC 4122 variant, so arithmetic or formatting with it can fail.
version + 0
import uuid
uuid.UUID(int=0).version + 0
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
check variant
import uuid
u = uuid.UUID(int=0)
u.version if u.variant == uuid.RFC_4122 else 0
0

When to use

Use it
  • Validating that an incoming ID is a uuid4 (or a uuid5 from your namespace)
  • Telling Microsoft GUIDs and legacy NCS UUIDs apart from RFC 4122 ones
Reach for something else
  • Checking the format of the text → UUID() parsing does that
  • Hand-written regexes for the version → u.version

Notes

CPython impl
variant tests bits 0x8000, 0x4000 and 0x2000 of the clock_seq field (int >> 48) in turn; version returns int((self.int >> 76) & 0xf) only when variant == RFC_4122, else falls off the end (None)
Versions
3.13 knows versions 1 to 5 (UUID(version=6) raises "illegal version number"). The 3.14 docs list versions 1 through 8 and say RFC_4122 is kept for backward compatibility although RFC 9562 superseded RFC 4122
Nil and Max
All zeros (nil) and all ones (max) are special UUIDs; 3.14 adds them as uuid.NIL and uuid.MAX

FAQ

uuid.UUID(text).version returns 1, 3, 4 or 5 for UUIDs made by the standard algorithms, and None when the variant is not RFC 4122.