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
- Use the typed overload identity.CompareTo(otherIdentity)
- Keep Identity values in typed containers so generic comparison is used
- Guard with a type test before object-based comparison
- 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
- Keep Identity values in strongly-typed containers
- Use the typed CompareTo(Identity) overload
- Narrow object inputs with pattern matching before comparing
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
- Argument must be a ConnectionId
- Argument must be a Uuid
- Expected Identity hex string to be 64 characters long, but w
- never types are not yet supported in C# output
- Issuer too long: {:?}
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/0a955a50b4bb9599.
Report an issue: GitHub.