clockworklabs/SpacetimeDB · error · ArgumentException

Argument must be a ConnectionId

Error message

Argument must be a ConnectionId

What it means

ConnectionId is the client's 128-bit connection identifier. Its untyped IComparable.CompareTo(object?) overload accepts only another ConnectionId or null (null sorts after); any other type throws ArgumentException.

Solutions

  1. Use the typed CompareTo(ConnectionId) overload
  2. Pattern-match boxed values before comparing
  3. Store connection ids in typed collections (ConnectionId[]) instead of object[]

Example fix

// before
int cmp = connectionId.CompareTo(otherObject); // ArgumentException: Argument must be a ConnectionId

// after
if (otherObject is ConnectionId other)
{
    int cmp = connectionId.CompareTo(other);
}
Defensive patterns

Strategy: type-guard

Validate before calling

static bool CanCompareWithConnectionId(object? other) => other is null || other is ConnectionId;

Type guard

static bool IsConnectionId(object? value) => value is ConnectionId;

Try / catch

try
{
    var cmp = ((IComparable)connectionId).CompareTo(boxed);
}
catch (ArgumentException)
{
    // convert to ConnectionId or reject the mixed comparison
}

Prevention

When it happens

Trigger: Calling CompareTo(object?) with a boxed Guid, Identity, string, or other non-ConnectionId value — through Array.Sort on object[], ArrayList, or manual object comparisons of subscriber/connection data.

Common situations: Sorting mixed id collections in subscription bookkeeping; comparing ids parsed from logs as object; generic comparison helpers.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/28dc8aee62912ccd. Report an issue: GitHub.

Appendix: source

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

        // --- / customized ---
    }

    public override string ToString() => Util.ToHexBigEndian(value);

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

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

[StructLayout(LayoutKind.Sequential)]
public readonly record struct Identity : IEquatable<Identity>, IComparable, IComparable<Identity>
{
    private readonly U256 value;

    internal Identity(U256 val) => value = val;

    /// <summary>
    /// Create an Identity from a LITTLE-ENDIAN byte array.
    ///
    /// If you are parsing an Identity from a string, you probably want FromHexString instead,

View on GitHub (pinned to 6dee26c6ef)