clockworklabs/SpacetimeDB · error · ArgumentNullException
Cannot serialize a null string as BSATN String. To…
Error message
Cannot serialize a null string as BSATN String. To serialize a null string you must use a nullable string (string?) so it is encoded as a BSATN option.
What it means
In BSATN, a plain string is a non-nullable primitive; null cannot be encoded as one. String.Write therefore throws ArgumentNullException, and the message states the fix: declare the field as string? (C# nullable) so the generator emits a BSATN option, which can represent absence.
Solutions
- Change the property/field to string? and update the module schema so it encodes as a BSATN option, then regenerate bindings
- If the column must stay non-nullable, guarantee a value before serialization (default to string.Empty or validate)
- Enable <Nullable>enable</Nullable> project-wide and fix the nullability warnings that appear
- Validate inbound payloads at the API boundary and reject nulls for non-nullable fields
Example fix
// before
public string Name { get; set; } = null!; // null slips through at runtime
row.Name = parsed.Name; // insert later throws ArgumentNullException
// after
public string? Name { get; set; } // BSATN option: null encodes as None
row.Name = parsed.Name; Defensive patterns
Strategy: validation
Validate before calling
// Ensure non-null before serializing a BSATN string field
static string EnsureBsatnString(string? value, string fieldName) =>
value ?? throw new InvalidOperationException($"{fieldName} must not be null; declare it as string? to encode a BSATN option."); Type guard
static bool IsSerializableBsatnString(string? s) => s is not null;
Try / catch
try
{
row.Write(writer);
}
catch (ArgumentNullException ex) when (ex.Message.Contains("BSATN String"))
{
// identify the null field and either default it or surface a domain error
} Prevention
- Enable <Nullable>enable</Nullable> and treat nullability warnings as errors
- Make genuinely optional columns string? (BSATN option) in the module schema
- Validate inbound payloads for nulls at the API boundary
- Default non-nullable strings to string.Empty rather than allowing null
When it happens
Trigger: Serializing a row or reducer argument whose non-nullable string property holds null at runtime — directly via the generated String BSATN Write, or indirectly during an insert/update/reducer call.
Common situations: Nullable reference types disabled or suppressed with the null-forgiving operator (!), so the compiler never flagged the null; JSON or external payload parsing injecting null into a 'required' string; schema evolution where the column should now be optional.
Related errors
- Value is out of range for enum
- Argument must be a I128
- Argument must be a I256
- Argument must be a U128
- Argument must be a U256
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/d1162b08a32c5bed.
Report an issue: GitHub.
Appendix: source
Thrown at crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs:560
writer.Write(value.Length);
writer.Write(value);
}
public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>
new AlgebraicType.Array(new AlgebraicType.U8(default));
}
// String is a special case of byte array with extra checks.
public readonly struct String : IReadWrite<string>
{
public string Read(BinaryReader reader) =>
Encoding.UTF8.GetString(ByteArray.Instance.Read(reader));
public void Write(BinaryWriter writer, string value)
{
if (value is null)
{
throw new ArgumentNullException(
nameof(value),
"Cannot serialize a null string as BSATN String. To serialize a null string you must use a nullable string (string?) so it is encoded as a BSATN option."
);
}
ByteArray.Instance.Write(writer, Encoding.UTF8.GetBytes(value));
}
public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>
new AlgebraicType.String(default);
}
public readonly struct List<Element, ElementRW> : IReadWrite<List<Element>>
where ElementRW : IReadWrite<Element>, new()
{
private static readonly Enumerable<Element, ElementRW> enumerable = new();
private static readonly ElementRW elementRW = new();
View on GitHub (pinned to 6dee26c6ef)