clockworklabs/SpacetimeDB · error · ArgumentException

Error while reading : expected source span to be bytes…

Error message

Error while reading {typeof(T).FullName}: expected source span to be {expectedSize} bytes long, but was {source.Length} bytes.

What it means

Util.Read<T> deserializes a blittable struct T directly over a ReadOnlySpan<byte> using MemoryMarshal.Read, which requires the span to be exactly Marshal.SizeOf<T>() bytes. A shorter or longer span throws ArgumentException naming the expected size (16 for ConnectionId, 32 for Identity).

Solutions

  1. Length-check the span against the expected width (16 for ConnectionId, 32 for Identity) before calling FromBigEndian
  2. Fix the upstream producer so it emits exactly the right byte width
  3. Prefer FromHexString, which validates the character count first with a clearer error

Example fix

// before
var id = Identity.FromBigEndian(Util.StringToByteArray(userInput)); // 20 bytes -> ArgumentException

// after
var id = Identity.FromHexString(userInput); // validates 64 hex chars first, clearer failure
Defensive patterns

Strategy: validation

Validate before calling

static bool IsConnectionIdBytes(ReadOnlySpan<byte> b) => b.Length == 16;
static bool IsIdentityBytes(ReadOnlySpan<byte> b) => b.Length == 32;

Try / catch

try
{
    id = Identity.FromBigEndian(source);
}
catch (ArgumentException ex)
{
    throw new FormatException($"Unexpected id width: {ex.Message}", ex);
}

Prevention

When it happens

Trigger: Calling ConnectionId.FromBigEndian/Identity.FromBigEndian (which delegate to Util.Read) with a span of the wrong length: hex decoded to the wrong byte count, a truncated payload, or a slice with the wrong end offset.

Common situations: Converting ids from hex or binary without validating width; interop with systems emitting different fixed-width ids; off-by-one slicing in parsers.

Related errors


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

Appendix: source

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

#endif
    }

    /// <summary>
    /// Convert the passed byte array to a value of type T, optionally reversing it before performing the conversion.
    /// If the input is not reversed, it is treated as having the native endianness of the host system.
    /// (The endianness of the host system can be checked via System.BitConverter.IsLittleEndian.)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"></param>
    /// <param name="littleEndian"></param>
    /// <returns></returns>
    public static T Read<T>(ReadOnlySpan<byte> source, bool littleEndian)
        where T : struct
    {
        var expectedSize = Marshal.SizeOf<T>();
        if (source.Length != expectedSize)
        {
            throw new ArgumentException(
                $"Error while reading {typeof(T).FullName}: expected source span to be {expectedSize} bytes long, but was {source.Length} bytes."
            );
        }

        var result = MemoryMarshal.Read<T>(source);

        if (littleEndian != BitConverter.IsLittleEndian)
        {
            AsBytes(ref result).Reverse();
        }

        return result;
    }

    /// <summary>
    /// Convert a hex string to a byte array.
    /// </summary>
    /// <param name="hex"></param>

View on GitHub (pinned to 6dee26c6ef)