{"record":{"id":"ffcbb70eb3824a3e","repo":"clockworklabs/SpacetimeDB","slug":"byte-array-must-be-exactly-size-bytes-long","errorCode":null,"errorMessage":"Byte array must be exactly {Size} bytes long.","messagePattern":"Byte array must be exactly (.+?) bytes long\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"crates/bindings-csharp/BSATN.Runtime/BSATN/U128.cs","lineNumber":42,"sourceCode":"    /// <summary>Initializes a new instance of the <see cref=\"U128\" /> struct.</summary>\n    /// <param name=\"upper\">The upper 64-bits of the 128-bit value.</param>\n    /// <param name=\"lower\">The lower 64-bits of the 128-bit value.</param>\n    public U128(ulong upper, ulong lower)\n    {\n        _upper = upper;\n        _lower = lower;\n    }\n\n    internal ulong Lower => _lower;\n\n    internal ulong Upper => _upper;\n\n    /// Returns a <see cref=\"U128\" /> from a big-endian byte array.\n    public static U128 FromBytesBigEndian(ReadOnlySpan<byte> bytes)\n    {\n        if (bytes.Length != Size)\n        {\n            throw new ArgumentException(\n                $\"Byte array must be exactly {Size} bytes long.\",\n                nameof(bytes)\n            );\n        }\n\n        var upper = BinaryPrimitives.ReadUInt64BigEndian(bytes[..8]);\n        var lower = BinaryPrimitives.ReadUInt64BigEndian(bytes[8..16]);\n\n        return new U128(upper, lower);\n    }\n\n    public byte[] ToBytesBigEndian()\n    {\n        var bytes = new byte[Size];\n\n        BinaryPrimitives.WriteUInt64BigEndian(bytes.AsSpan(0, 8), _upper);\n        BinaryPrimitives.WriteUInt64BigEndian(bytes.AsSpan(8, 8), _lower);\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/bindings-csharp/BSATN.Runtime/BSATN/U128.cs#L24-L60","documentation":"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.","triggerScenarios":"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.","commonSituations":"Converting GUIDs or digests into U128-backed types (Uuid, Identity) with wrong slicing; interop code assuming different fixed widths; off-by-one parsing loops.","solutions":["Check bytes.Length == 16 (U128.Size) and slice the source to exactly 16 bytes before calling","Fix the upstream producer (e.g. hex string must decode to 16 bytes)","If the value is 32 bytes, use U256.FromBytesBigEndian instead"],"exampleFix":"// before\nvar u = U128.FromBytesBigEndian(hash[..8]); // ArgumentException: Byte array must be exactly 16 bytes long.\n\n// after\nvar u = U128.FromBytesBigEndian(hash[..16]); // exactly 16 bytes","handlingStrategy":"validation","validationCode":"static bool IsU128Bytes(ReadOnlySpan<byte> bytes) => bytes.Length == U128.Size; // 16","typeGuard":null,"tryCatchPattern":"try\n{\n    value = U128.FromBytesBigEndian(source);\n}\ncatch (ArgumentException ex)\n{\n    throw new FormatException($\"Expected 16 bytes for U128, got {source.Length}\", ex);\n}","preventionTips":["Centralize width constants (16 for U128, 32 for U256) instead of magic numbers","Prefer FromHexString-style entry points that validate length up front","Double-check slice bounds when carving buffers for id conversion"],"tags":["csharp","spacetimedb","bsatn","uint128","bytemanipulation"],"backgroundTag":"byte-array-length-mismatch","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}