Nil UUID and Max UUID: What They Are and When to Use Them
By SimpleTools24Published 3 min read
The nil UUID is the special UUID with all 128 bits set to zero: 00000000-0000-0000-0000-000000000000. The max UUID has all bits set to one: ffffffff-ffff-ffff-ffff-ffffffffffff. RFC 9562 defines both as special-case values outside the normal version and variant rules. The nil UUID commonly means "no value" or "not set", and .NET calls it Guid.Empty; the max UUID can serve as a sentinel, such as an upper bound in ranges.
In this guide
What the Standard Says
RFC 9562, published in 2024, defines:
- Nil UUID: all bits zero. Long recognised in earlier specifications too.
- Max UUID: all bits one. Newly named in RFC 9562.
Neither follows the version and variant layout of normal UUIDs. A strict validator that checks for versions 1–8 and the standard variant will reject both unless it allows them explicitly.
How Languages Represent Them
| Language / platform | Nil UUID | Max UUID |
|---|---|---|
| .NET | Guid.Empty | Guid.AllBitsSet (.NET 9+) |
| Python 3.14+ | uuid.NIL | uuid.MAX |
| Java | new UUID(0L, 0L) | new UUID(-1L, -1L) |
| JavaScript (uuid package) | NIL export | MAX export (recent versions) |
| PostgreSQL | '00000000-0000-0000-0000-000000000000'::uuid | 'ffffffff-ffff-ffff-ffff-ffffffffffff'::uuid |
Legitimate Uses
"No Value" Without NULL
Some systems use the nil UUID instead of NULL where a column can't be nullable, or where a struct type (like .NET's Guid) can't be null. It's a recognisable placeholder: "this reference hasn't been set".
Sentinels and Boundaries
The max UUID can mark an upper bound when paginating or partitioning by UUID ranges, and the nil UUID a lower bound.
Tests and Fixtures
Both are handy as obviously fake, deterministic values in tests.
When a Nil UUID Is a Bug
Unexpected nil UUIDs in production data usually point to a mistake:
- Uninitialised fields. In C#, a
Guidproperty defaults toGuid.Empty. If code forgets to assignGuid.NewGuid(), records get saved with the nil value.new Guid()also returnsGuid.Empty, a frequent typo. - Failed parsing with a fallback. Some code returns the nil UUID when parsing fails, silently turning bad input into a "valid" ID.
- Serialisation defaults. Missing JSON fields deserialised into non-nullable UUID types become nil.
- Unique constraint collisions. If several records are saved with the nil UUID, a unique key will reject the second one, which is often how the bug is discovered.
Treat a nil UUID arriving from outside as invalid for most identifiers, and guard against saving it:
if (entity.Id == Guid.Empty) throw new InvalidOperationException("Id not set");import uuid
if value == uuid.UUID(int=0):
raise ValueError("nil UUID is not a valid identifier here")Validation Policy
Decide explicitly:
- Accept as "unset": only if your data model uses it that way.
- Reject: for IDs that must point to real records, which is most of them.
- Accept max UUID: almost never as a record ID; only as an internal boundary.
UUID regex patterns shows a strict pattern that excludes both, and why a UUID is invalid covers other input problems. If you're working in .NET, how to generate a GUID in C# explains the new Guid() trap in context.
Spotting Them in Your Data
When debugging, paste a list of IDs into the UUID validator. It checks up to 1,000 values, recognises nil and max UUIDs, and shows each valid value's version, variant and canonical form, so all-zero placeholders stand out quickly.
Nil UUID in APIs and JSON
APIs sometimes return the nil UUID where null would be clearer:
{ "orderId": "8b0c...", "parentOrderId": "00000000-0000-0000-0000-000000000000" }Clients then have to know that the nil value means "none". If you design the API, prefer null or omitting the field. If you consume one, map the nil UUID to your language's null or empty value at the boundary, so the rest of your code doesn't need to know about the convention.
Databases
- PostgreSQL stores the nil UUID like any other value; a
NOT NULLcolumn will happily accept it, which can hide missing data. - SQL Server
uniqueidentifiercolumns behave the same way. - A
CHECKconstraint can block it where it should never appear:
ALTER TABLE orders
ADD CONSTRAINT orders_id_not_nil
CHECK (id <> '00000000-0000-0000-0000-000000000000');Frequently Asked Questions
Is the nil UUID a valid UUID?
Yes. It's a special value defined by the standard, though it doesn't have a version.
What is Guid.Empty?
.NET's name for the nil UUID, 00000000-0000-0000-0000-000000000000.
Should I store nil UUIDs or NULL?
Prefer NULL for "no value" where the database and language allow it. It's clearer and works naturally with constraints.
When was the max UUID introduced?
RFC 9562 (May 2024) formally defined it.
Summary
Nil (all zeros) and max (all f's) are special UUIDs outside the version rules. Use them deliberately as placeholders or bounds, and treat an unexpected nil UUID as a bug to fix at its source.
Related tools
Sources
- RFC 9562 – Section 5.9 Nil UUID and Section 5.10 Max UUID – IETF (opens in a new tab)
Related articles
- UUID Format ExplainedThe 8-4-4-4-12 layout, where the version and variant live, and the text forms systems accept.
- Why Is My UUID Invalid?The usual reasons a UUID gets rejected, from invisible whitespace to truncation, and how to fix each.
- Generate a GUID in C#Guid.NewGuid(), Guid.CreateVersion7(), format specifiers, parsing and the mistakes to avoid in .NET.