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

  1. Use the strongly-typed overload: uuid.CompareTo(otherUuid), or the <, >, operators
  2. Keep collections strongly typed (Uuid[], List<Uuid>) so the generic comparer is used
  3. Type-check before comparing: if (obj is Uuid other) ... else handle mismatch explicitly
  4. 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

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


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