clockworklabs/SpacetimeDB · error · ArgumentException
Argument must be a Uuid
Error message
Argument must be a Uuid
What it means
The non-generic IComparable.CompareTo(object) implementation on Uuid throws ArgumentException for any argument that is neither a Uuid nor null (null compares as greater, returning 1). It exists to satisfy object-based comparison APIs and intentionally rejects other types instead of attempting a meaningless ordering.
Source
Thrown at crates/bindings-csharp/BSATN.Runtime/BSATN/Uuid.cs:309
return ToGuid().ToString();
}
public readonly int CompareTo(Uuid other) => value.CompareTo(other.value);
/// <inheritdoc cref="IComparable.CompareTo(object)" />
public int CompareTo(object? value)
{
if (value is Uuid other)
{
return CompareTo(other);
}
else if (value is null)
{
return 1;
}
else
{
throw new ArgumentException("Argument must be a Uuid", nameof(value));
}
}
public static bool operator <(Uuid l, Uuid r) => l.CompareTo(r) < 0;
public static bool operator >(Uuid l, Uuid r) => l.CompareTo(r) > 0;
public readonly partial struct BSATN : IReadWrite<Uuid>
{
public Uuid Read(BinaryReader reader) => new(new SpacetimeDB.BSATN.U128Stdb().Read(reader));
public void Write(BinaryWriter writer, Uuid value) =>
new SpacetimeDB.BSATN.U128Stdb().Write(writer, value.value);
// --- / auto-generated ---
// --- customized ---
public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>View on GitHub (pinned to 524b4487d9)
Solutions
- Use the strongly-typed overload: uuid.CompareTo(otherUuid), or the <, >, operators
- Keep collections strongly typed (Uuid[], List<Uuid>) so the generic comparer is used
- Type-check before comparing: if (obj is Uuid other) ... else handle mismatch explicitly
- In mixed-type stores, compare on a normalized key (e.g., the 32-char hex string) instead of the raw object
Example fix
// before
int c = ((IComparable)idA).CompareTo(boxedValue); // throws if not Uuid
// after
int c = boxedValue is Uuid other ? idA.CompareTo(other) : throw new ArgumentException($"Cannot compare Uuid with {boxedValue?.GetType().Name}", nameof(boxedValue)); Defensive patterns
Strategy: type-guard
Type guard
static int CompareSafe(Uuid left, object? right) =>
right switch
{
null => 1,
Uuid u => left.CompareTo(u),
_ => throw new ArgumentException($"Cannot compare Uuid with {right.GetType().Name}", nameof(right)),
}; Try / catch
try { result = ((IComparable)uuid).CompareTo(boxed); }
catch (ArgumentException) { /* heterogeneous data; fall back to comparing hex strings */ result = uuid.ToHexString().CompareTo(boxed?.ToString()); } Prevention
- Keep Uuid collections strongly typed (List<Uuid>, Uuid[]) so generic comparison is used
- Prefer the typed CompareTo(Uuid) overload in all new code
- Type-check before any object-typed comparison API
When it happens
Trigger: Invoking ((IComparable)uuid).CompareTo(someString); sorting/searching a mixed object[] or ArrayList containing Uuids and other types; passing a boxed value of another type through Comparer.Default or a non-generic BinarySearch/Sort key.
Common situations: Interfacing with old non-generic collections or serialization frameworks that call CompareTo(object); logging/dedup code that compares keys of heterogeneous provenance; copy-pasted comparison helpers typed as object.
Related errors
- Argument must be a ConnectionId
- Argument must be a Identity
- uuid counter must be non-negative
- timestamp before unix epoch
- Unknown UUID version
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/1dd77a551b4e9e2e.
Report an issue: GitHub.