clockworklabs/SpacetimeDB · error · ArgumentException

Argument must be a Identity

Error message

Argument must be a Identity

What it means

The non-generic IComparable.CompareTo(object) on Identity throws ArgumentException for arguments that are neither an Identity nor null (null returns 1). Like the other SpacetimeDB ID structs, it deliberately rejects unrelated types rather than inventing an ordering.

Source

Thrown at crates/bindings-csharp/BSATN.Runtime/Builtins.cs:337

    }

    // This must be explicitly implemented, otherwise record will generate a new implementation.
    public override string ToString() => Util.ToHexBigEndian(value);

    /// <inheritdoc cref="IComparable.CompareTo(object)" />
    public int CompareTo(object? value)
    {
        if (value is Identity other)
        {
            return CompareTo(other);
        }
        else if (value is null)
        {
            return 1;
        }
        else
        {
            throw new ArgumentException("Argument must be a Identity", nameof(value));
        }
    }

    /// <inheritdoc cref="IComparable{T}.CompareTo(T)" />
    public int CompareTo(Identity identity) => this.value.CompareTo(identity.value);
}

/// <summary>
/// A timestamp that represents a unique moment in time (in the Earth's reference frame).
///
/// This type may be converted to/from a DateTimeOffset, but the conversion can lose precision.
/// This type has less precision than DateTimeOffset (units of microseconds rather than units of 100ns).
/// </summary>
[StructLayout(LayoutKind.Sequential)] // we should be able to use it in FFI
public record struct Timestamp(long MicrosecondsSinceUnixEpoch)
    : IStructuralReadWrite,
        IComparable<Timestamp>
{

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Use the typed overload identity.CompareTo(otherIdentity)
  2. Keep Identity values in typed containers so generic comparison is used
  3. Guard with a type test before object-based comparison
  4. Use the hex string as the comparison key across heterogeneous systems

Example fix

// before
object key = GetSortKey();
int c = ((IComparable)identity).CompareTo(key); // throws for non-Identity

// after
int c = key is Identity other ? identity.CompareTo(other) : throw new InvalidOperationException($"Cannot compare Identity with {key?.GetType().Name}");
Defensive patterns

Strategy: type-guard

Type guard

static bool IsIdentity(object? o) => o is Identity;

Prevention

When it happens

Trigger: ((IComparable)identity).CompareTo(boxed); non-generic sorts/searches over object[] or ArrayList mixing Identity with strings/Guids; reflection-based frameworks invoking CompareTo(object).

Common situations: Interop with non-generic or reflection-heavy libraries (serialization, grid sorting); shared comparison helpers typed as object.

Related errors


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