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-endianView on GitHub (pinned to 524b4487d9)
Solutions
- 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)
- Only produce IDs via the library's own generators (Uuid.RandomV4 / FromCounterV7) so versions stay supported
- If the column genuinely holds arbitrary U128s, use SpacetypeDB's U128 type instead of Uuid
- 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
- Generate IDs only through this library so version nibbles stay 4 or 7
- Do not wrap arbitrary U128 column values in Uuid if you plan to query versions
- Re-key imported v1/v5/v6/v8 identifiers to v4/v7 at migration time
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
- uuid counter must be non-negative
- timestamp before unix epoch
- `fromCounterV7` requires `randomBytes.length == 4`
- `fromCounterV7` uuid `counter` must be non-negative
- `fromCounterV7` `timestamp` before unix epoch
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/5ac017e12aec02ac.
Report an issue: GitHub.