{"record":{"id":"d1162b08a32c5bed","repo":"clockworklabs/SpacetimeDB","slug":"cannot-serialize-a-null-string-as-bsatn-string-to","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs","lineNumber":560,"sourceCode":"        writer.Write(value.Length);\n        writer.Write(value);\n    }\n\n    public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>\n        new AlgebraicType.Array(new AlgebraicType.U8(default));\n}\n\n// String is a special case of byte array with extra checks.\npublic readonly struct String : IReadWrite<string>\n{\n    public string Read(BinaryReader reader) =>\n        Encoding.UTF8.GetString(ByteArray.Instance.Read(reader));\n\n    public void Write(BinaryWriter writer, string value)\n    {\n        if (value is null)\n        {\n            throw new ArgumentNullException(\n                nameof(value),\n                \"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.\"\n            );\n        }\n\n        ByteArray.Instance.Write(writer, Encoding.UTF8.GetBytes(value));\n    }\n\n    public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>\n        new AlgebraicType.String(default);\n}\n\npublic readonly struct List<Element, ElementRW> : IReadWrite<List<Element>>\n    where ElementRW : IReadWrite<Element>, new()\n{\n    private static readonly Enumerable<Element, ElementRW> enumerable = new();\n    private static readonly ElementRW elementRW = new();\n","sourceCodeStart":542,"sourceCodeEnd":578,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs#L542-L578","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\npublic string Name { get; set; } = null!; // null slips through at runtime\nrow.Name = parsed.Name; // insert later throws ArgumentNullException\n\n// after\npublic string? Name { get; set; } // BSATN option: null encodes as None\nrow.Name = parsed.Name;","handlingStrategy":"validation","validationCode":"// Ensure non-null before serializing a BSATN string field\nstatic string EnsureBsatnString(string? value, string fieldName) =>\n    value ?? throw new InvalidOperationException($\"{fieldName} must not be null; declare it as string? to encode a BSATN option.\");","typeGuard":"static bool IsSerializableBsatnString(string? s) => s is not null;","tryCatchPattern":"try\n{\n    row.Write(writer);\n}\ncatch (ArgumentNullException ex) when (ex.Message.Contains(\"BSATN String\"))\n{\n    // identify the null field and either default it or surface a domain error\n}","preventionTips":["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"],"tags":["csharp","spacetimedb","bsatn","null","serialization"],"backgroundTag":"null-value-serialization","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"}