-
Notifications
You must be signed in to change notification settings - Fork 1
Source Generator produces empty array for byte[] properties — WriteBinary is never called #27
Description
Package version
4.0.2
Affected package
BLite (client SDK)
.NET version
10.0
Description
When an entity contains a byte[]? property, the Source Generator produces serialization code that writes an empty BSON array ([]) regardless of the actual data. The property is silently discarded on every write and read, resulting in permanent data loss with no compiler warning.
The root cause is that EntityAnalyzer classifies byte[] as a collection (IsCollection = true, CollectionItemType = "byte"). The collection serialization branch in CodeGenerator.GenerateWriteProperty then calls GetPrimitiveWriteMethod with type name "byte", which returns null because "byte" is not in the primitive type mapping table. When writeMethod == null, the foreach loop body contains no write call — nothing is written per element. Only BeginArray / EndArray wrappers are emitted, producing an empty BSON array.
Meanwhile, BsonSpanWriter.WriteBinary does exist and correctly writes BSON Binary data (type 0x05). The Source Generator simply never generates a call to it for byte[] properties.
Minimal reproduction
Entity definition
public class Photo
{
public Guid Id { get; set; }
public byte[]? ThumbHashData { get; set; }
}DbContext
public class AppDbContext : BLiteDbContext
{
public DocumentCollection<Photo> Photos { get; set; } = null!;
}Write and read back
using var db = new AppDbContext("PhotoIndex");
var photo = new Photo
{
Id = Guid.NewGuid(),
ThumbHashData = new byte[] { 0x01, 0x02, 0x03, 0x04 }
};
db.Photos.Upsert(photo);
var retrieved = db.Photos.FindById(photo.Id);
// retrieved.ThumbHashData is Array.Empty<byte>() — data is silently lostGenerated source code (actual)
This is what the Source Generator produces for the byte[]? ThumbHashData property.
Serialization — writes empty array, data is lost
if (entity.ThumbHashData != null)
{
var thumbhashdataArrayPos = writer.BeginArray("thumbhashdata");
var thumbhashdataIndex = 0;
foreach (var item in entity.ThumbHashData)
{
// BUG: GetPrimitiveWriteMethod("byte") returns null,
// so no write call is generated here — data is silently dropped
thumbhashdataIndex++;
}
writer.EndArray(thumbhashdataArrayPos); // writes BSON []
}
else
{
writer.WriteNull("thumbhashdata");
}Deserialization — never reads any elements
var thumbhashdata = new global::System.Collections.Generic.List<byte>();
// ...
case "thumbhashdata":
if (bsonType == global::BLite.Bson.BsonType.Null) break;
var thumbhashdataArrSize = reader.ReadDocumentSize();
var thumbhashdataArrEndPos = reader.Position + thumbhashdataArrSize - 4;
while (reader.Position < thumbhashdataArrEndPos)
{
var itemType = reader.ReadBsonType();
if (itemType == global::BLite.Bson.BsonType.EndOfDocument) break;
reader.SkipArrayKey();
// BUG: GetPrimitiveReadMethod("byte") returns null,
// falls through to SkipValue — every element is skipped
reader.SkipValue(itemType);
}
break;
// ...
entity.ThumbHashData = thumbhashdata.ToArray();
// Result: always Array.Empty<byte>()In practice, since serialization writes an empty array [], the while loop never executes (immediately hits EndOfDocument), and thumbhashdata is always an empty List<byte>. The final .ToArray() always produces Array.Empty<byte>().
Expected behavior
For byte[] properties, the Source Generator should generate a call to BsonSpanWriter.WriteBinary / BsonSpanReader.ReadBinary instead of treating it as a collection of individual byte elements.
Note: BsonSpanWriter.WriteBinary and BsonSpanReader.ReadBinary already exist:
// BsonSpanWriter.cs
public void WriteBinary(string name, ReadOnlySpan<byte> data, byte subtype = 0)
// BsonSpanReader.cs
public ReadOnlySpan<byte> ReadBinary(out byte subtype)Expected serialization:
if (entity.ThumbHashData != null)
{
writer.WriteBinary("thumbhashdata", entity.ThumbHashData);
}
else
{
writer.WriteNull("thumbhashdata");
}Expected deserialization:
case "thumbhashdata":
if (bsonType == global::BLite.Bson.BsonType.Null)
{
thumbhashdata = null;
}
else
{
thumbhashdata = reader.ReadBinary(out _).ToArray();
}
break;Actual behavior
- Serialization: An empty BSON array
[]is written. The byte data is completely lost. - Deserialization: The property is always read back as
Array.Empty<byte>(). - No compiler warning: Unlike unsupported complex types that generate
#warning, the bug is completely silent — data loss occurs without any build-time indication.
Additional context
WriteBinary/ReadBinaryalready exist inBsonSpanWriter/BsonSpanReader, so this is purely a Source Generator oversight.GetWriteMethodForUnderlyingTypemaps"byte"→"WriteInt32", but this code path is only used for enum underlying types, not for collection item serialization.- The fix should be in either
EntityAnalyzer(special-casebyte[]as a binary property rather than a collection) orCodeGenerator(detectCollectionItemType == "byte"and emit a singleWriteBinarycall instead of iterating).