clockworklabs/SpacetimeDB · error · InvalidOperationException

Unknown UUID version

Error message

Unknown UUID version

What it means

Uuid.GetVersion() decodes the version nibble (byte 6 high bits) and only recognizes 4 (random) and 7 (time-ordered), plus the special all-zero NIL and all-one MAX values. Any other 128-bit value - v1 time-based, v5 name-based, v6, v8, or a raw U128 that is not a UUID at all - throws InvalidOperationException.

Source

Thrown at crates/bindings-csharp/BSATN.Runtime/BSATN/Uuid.cs:218

    }

    /// <summary>
    /// Returns the <see cref="UuidVersion"/> of this <see cref="Uuid"/>.
    ///
    /// Throws <see cref="InvalidOperationException"/> if the <see cref="Uuid"/> version is unknown.
    /// </summary>
    public UuidVersion GetVersion()
    {
        var bytes = value.ToBytesBigEndian();
        var version = (bytes[6] >> 4) & 0x0F;

        return version switch
        {
            4 => UuidVersion.V4,
            7 => UuidVersion.V7,
            _ => this == Uuid.NIL ? UuidVersion.Nil
            : this == Uuid.MAX ? UuidVersion.Max
            : throw new InvalidOperationException("Unknown UUID version"),
        };
    }

    private static void GuidToBigEndianBytes(ReadOnlySpan<byte> guidBytes, Span<byte> be)
    {
        // Guid’s weird internal layout (mixed-endian)

        // time_low (4 bytes) — little-endian → reverse
        be[0] = guidBytes[3];
        be[1] = guidBytes[2];
        be[2] = guidBytes[1];
        be[3] = guidBytes[0];

        // time_mid (2 bytes) — little-endian
        be[4] = guidBytes[5];
        be[5] = guidBytes[4];

        // time_hi_and_version (2 bytes) — little-endian

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Check the version nibble yourself before calling GetVersion: (value.ToBytesBigEndian()[6] >> 4) must be 4 or 7 (or the value equals Uuid.NIL / Uuid.MAX)
  2. Only produce IDs via the library's own generators (Uuid.RandomV4 / FromCounterV7) so versions stay supported
  3. If the column genuinely holds arbitrary U128s, use SpacetypeDB's U128 type instead of Uuid
  4. Re-key legacy v1/v5 identifiers to v4/v7 at import time

Example fix

// before
var u = new Uuid(U128.FromBytesBigEndian(rawBytes));
var v = u.GetVersion(); // throws for v1/v5/v6/v8/raw data

// after
static UuidVersion SafeVersion(Uuid u) =>
    u == Uuid.NIL ? UuidVersion.Nil
    : u == Uuid.MAX ? UuidVersion.Max
    : (u.ToBytesBigEndian()[6] >> 4) switch { 4 => UuidVersion.V4, 7 => UuidVersion.V7, _ => (UuidVersion)(-1) };
Defensive patterns

Strategy: validation

Validate before calling

static bool IsSupportedUuid(Uuid u)
{
    if (u == Uuid.NIL || u == Uuid.MAX) return true;
    var v = (u.ToBytesBigEndian()[6] >> 4) & 0x0F;
    return v is 4 or 7;
}

if (IsSupportedUuid(id)) { var ver = id.GetVersion(); }

Try / catch

UuidVersion ver;
try { ver = id.GetVersion(); }
catch (InvalidOperationException) { ver = default; /* treat as unknown/opaque */ }

Prevention

When it happens

Trigger: Constructing a Uuid from a Guid produced by external systems that emit v1/v5/v6/v8; wrapping an arbitrary U128/I128 database column in a Uuid and calling GetVersion(); parsing corrupted or truncated bytes.

Common situations: Migrating IDs from legacy systems using time-based v1 GUIDs (common on Windows/SQL Server); storing non-UUID 128-bit values in a column typed as Uuid; interop with Node/Python libs generating v6/v8.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/5ac017e12aec02ac. Report an issue: GitHub.