clockworklabs/SpacetimeDB · error · ArgumentException

Byte array must be exactly

Error message

Byte array must be exactly {Size} bytes long.

What it means

U128.FromBytesBigEndian constructs a 128-bit unsigned integer from exactly 16 big-endian bytes (U128.Size). Any other length throws ArgumentException because a buffer of the wrong size cannot unambiguously populate the upper and lower 64-bit halves.

Solutions

  1. Check bytes.Length == 16 (U128.Size) and slice the source to exactly 16 bytes before calling
  2. Fix the upstream producer (e.g. hex string must decode to 16 bytes)
  3. If the value is 32 bytes, use U256.FromBytesBigEndian instead

Example fix

// before
var u = U128.FromBytesBigEndian(hash[..8]); // ArgumentException: Byte array must be exactly 16 bytes long.

// after
var u = U128.FromBytesBigEndian(hash[..16]); // exactly 16 bytes
Defensive patterns

Strategy: validation

Validate before calling

static bool IsU128Bytes(ReadOnlySpan<byte> bytes) => bytes.Length == U128.Size; // 16

Try / catch

try
{
    value = U128.FromBytesBigEndian(source);
}
catch (ArgumentException ex)
{
    throw new FormatException($"Expected 16 bytes for U128, got {source.Length}", ex);
}

Prevention

When it happens

Trigger: Passing a span/array whose length is not exactly 16: hex-decoding a shortened string, slicing with the wrong range (bytes[..8]), or feeding variable-length hash/digest output.

Common situations: Converting GUIDs or digests into U128-backed types (Uuid, Identity) with wrong slicing; interop code assuming different fixed widths; off-by-one parsing loops.

Related errors


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

Appendix: source

Thrown at crates/bindings-csharp/BSATN.Runtime/BSATN/U128.cs:42

    /// <summary>Initializes a new instance of the <see cref="U128" /> struct.</summary>
    /// <param name="upper">The upper 64-bits of the 128-bit value.</param>
    /// <param name="lower">The lower 64-bits of the 128-bit value.</param>
    public U128(ulong upper, ulong lower)
    {
        _upper = upper;
        _lower = lower;
    }

    internal ulong Lower => _lower;

    internal ulong Upper => _upper;

    /// Returns a <see cref="U128" /> from a big-endian byte array.
    public static U128 FromBytesBigEndian(ReadOnlySpan<byte> bytes)
    {
        if (bytes.Length != Size)
        {
            throw new ArgumentException(
                $"Byte array must be exactly {Size} bytes long.",
                nameof(bytes)
            );
        }

        var upper = BinaryPrimitives.ReadUInt64BigEndian(bytes[..8]);
        var lower = BinaryPrimitives.ReadUInt64BigEndian(bytes[8..16]);

        return new U128(upper, lower);
    }

    public byte[] ToBytesBigEndian()
    {
        var bytes = new byte[Size];

        BinaryPrimitives.WriteUInt64BigEndian(bytes.AsSpan(0, 8), _upper);
        BinaryPrimitives.WriteUInt64BigEndian(bytes.AsSpan(8, 8), _lower);

View on GitHub (pinned to 6dee26c6ef)