UUID byte order: big-endian, and the Microsoft exception

byte array7 sectionsUpdated

RFC 9562 stores a UUID big-endian: the printed order is the byte order. Microsoft APIs store the first three fields little-endian, so the same identifier turns into a different byte array, and reading one as the other silently produces a different UUID.

Almost every UUID bug that survives code review is a byte order bug. The text form is unambiguous; the byte form is not, because one large ecosystem writes the first three fields in the opposite order. This page shows both byte arrays for the same identifier, and how to detect which one you have.

byte arraycomputed by the converter itself
inf81d4fae-7dec-11d0-a765-00a0c91e6bf6outf8 1d 4f ae 7d ec 11 d0 a7 65 00 a0 c9 1e 6b f6

Mixed-endian, the same identifier: ae 4f 1d f8 ec 7d d0 11 a7 65 00 a0 c9 1e 6b f6

in0c5b2444-70a0-4932-980c-b4dc0d3f02b5out0c 5b 24 44 70 a0 49 32 98 0c b4 dc 0d 3f 02 b5

Mixed-endian: 44 24 5b 0c a0 70 32 49 98 0c b4 dc 0d 3f 02 b5

Open the converter: byte arrayNothing you paste leaves the browser.
On this page (7)

What actually gets swapped#

A UUID prints as five groups: 8-4-4-4-12 hex digits. The mixed-endian layout reverses the bytes of the first three groups and leaves the last two alone. The fourth and fifth groups are byte arrays in both layouts, which is why an identifier can look half-familiar after the wrong conversion: the tail matches, the head does not.

GroupRFC 9562 orderMicrosoft in-memory order
1 (4 bytes)big-endianlittle-endian
2 (2 bytes)big-endianlittle-endian
3 (2 bytes)big-endianlittle-endian
4 (2 bytes)as writtenas written
5 (6 bytes)as writtenas written

RFC 9562 § 4 · UUID FormatThe standard states the byte order once, at the top: most significant byte first

Which systems hand you which#

SourceByte orderNote
Guid.ToByteArray() in .NETmixed-endianGuid.ToByteArray(bigEndian: true) exists in .NET 8 and later
SQL Server uniqueidentifiermixed-endian in binary formIts comparison starts from the last group, which is why GUID clustered keys sort strangely
Java UUID, Go [16]byte, Python uuid.bytesbig-endianPython also offers bytes_le for the mixed form
MongoDB BSON subtype 4big-endianThe standard subtype; use this one
MongoDB BSON subtype 3driver-dependentLegacy. The C# driver wrote mixed-endian, others did not
UUID_TO_BIN(u, 1) in MySQLbig-endian, reorderedSwaps time_low and time_high for index locality — a different operation, not endianness

How to tell which one you have#

Byte 6 carries the version in its high nibble in the RFC order, so a v4 shows 4x there and a v7 shows 7x. Swapping moves that nibble into byte 7 and pulls a different byte into its place, so the decoded version changes.

What it changes into is the catch. Decoding twenty thousand swapped v4 identifiers spreads the version nibble evenly across all sixteen values, so a little over half of them still read as a version somebody could plausibly have generated. The variant nibble does not help either: groups four and five are untouched by the swap, so it stays exactly where it was.

A single value therefore cannot be diagnosed by eye. What does work: decode a batch. A source that really produces v4 shows the digit 4 in every single one, and a swapped batch shows all sixteen digits in roughly equal numbers. For one value, round-trip it through the library that wrote the bytes and compare the text with what you expected.

csharp
var id = new Guid("f81d4fae-7dec-11d0-a765-00a0c91e6bf6");

byte[] mixed = id.ToByteArray();            // ae 4f 1d f8 …
byte[] rfc   = id.ToByteArray(bigEndian: true);  // f8 1d 4f ae …  (.NET 8+)

// before .NET 8: swap groups 1-3 by hand
Array.Reverse(mixed, 0, 4);
Array.Reverse(mixed, 4, 2);
Array.Reverse(mixed, 6, 2);

The rule that prevents all of this#

Store and transport the text form, or store the RFC byte order and write down that you did. A binary column with no note attached is a trap for the next service that reads it, and the failure is silent: you get a valid-looking UUID that belongs to nobody.

RFC 4122 § 4.1.2 · Layout and Byte OrderThe layout the older standard described, for systems still built on it

Questions people actually ask#

Why does the same GUID look different in C# and in Java?

Guid.ToByteArray writes the first three fields little-endian; Java writes all sixteen bytes big-endian. The text form is identical, the byte arrays are not.

Is mixed-endian the same as little-endian?

No. Only the first three fields are reversed; the last eight bytes keep their order. That is why the tail of the identifier still matches after a wrong conversion.

How do I detect a swapped UUID?

Not from one value: half of all swapped v4s still decode as a plausible version. Decode a batch instead — a correct source shows one version digit for every identifier, a swapped one shows all sixteen.

Browse the reference