{"record":{"id":"b0595cab65a8da78","repo":"clockworklabs/SpacetimeDB","slug":"value-value-is-out-of-range-for-enum-typeof-t","errorCode":null,"errorMessage":"Value {value} is out of range for enum {typeof(T).Name}","messagePattern":"Value (.+?) is out of range for enum (.+?)","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs","lineNumber":172,"sourceCode":"        // This was quite expensive because:\n        //   1. It uses reflection\n        //   2. It allocates\n        //   3. It is called on each row when decoding\n        //\n        // However, enum values are guaranteed to be sequential and zero based.\n        // Hence we only ever need to do an upper bound check.\n        // See `SpacetimeDB.Type.ParseEnum` for the syntax analysis.\n        //\n        // Note: this actually still uses reflection and allocates.\n        // It's hard to figure out how to avoid this without custom-generating a writer for each enum type.\n        var tag = Convert.ToByte(value);\n        if (tag < TagToValue.Length)\n        {\n            writer.Write(tag);\n        }\n        else\n        {\n            throw new ArgumentOutOfRangeException(\n                $\"Value {value} is out of range for enum {typeof(T).Name}\"\n            );\n        }\n    }\n\n    public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>\n        registrar.RegisterType<T>(\n            (_) =>\n                new AlgebraicType.Sum(\n#pragma warning disable CA2263 // netstandard2.1 lacks the generic Enum overloads.\n                    [\n                        .. Enum.GetNames(typeof(T))\n                            .Select(name => new AggregateElement(name, AlgebraicType.Unit)),\n                    ]\n#pragma warning restore CA2263\n                )\n        );\n}","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs#L154-L190","documentation":"The BSATN enum writer converts the enum value to its tag byte and only writes tags below the variant count, because SpacetimeDB enums must be zero-based and contiguous. A value whose numeric tag is >= the number of variants throws ArgumentOutOfRangeException on Write.","triggerScenarios":"Serializing an enum with explicit values that are not 0..N-1 — e.g. enum Status { Active = 1, Inactive = 2, Pending = 3 } makes the last variant convert to tag 3 with only 3 valid tags (0-2). Also (Status)99 cast from a raw int.","commonSituations":"Porting an existing C# enum that started at 1 or reserved specific numbers for interop with other systems; casting unchecked ints to the enum type before an insert or reducer call.","solutions":["Make the enum zero-based and contiguous by removing explicit values: enum Status { Active, Inactive, Pending }","If explicit values are required, keep them contiguous and within 0..N-1","Validate values before serializing: reject any enum whose numeric value is outside 0..count-1","After fixing the enum, regenerate bindings so client and module agree on tags"],"exampleFix":"// before\npublic enum Status { Active = 1, Inactive = 2, Pending = 3 } // Pending -> tag 3 >= 3 variants -> throws\n\n// after\npublic enum Status { Active, Inactive, Pending } // tags 0..2, all valid","handlingStrategy":"validation","validationCode":"static bool IsBsatnEnumValueInRange<TEnum>(TEnum value)\n    where TEnum : struct, Enum\n{\n    var tag = Convert.ToInt32(value);\n    return tag >= 0 && tag < Enum.GetValues(typeof(TEnum)).Length;\n}","typeGuard":"static bool IsContiguousZeroBasedEnum<TEnum>() where TEnum : struct, Enum\n{\n    var values = Enum.GetValues(typeof(TEnum)).Cast<int>().OrderBy(v => v).ToArray();\n    return values.Select((v, i) => v == i).All(ok => ok);\n}","tryCatchPattern":null,"preventionTips":["Define module enums without explicit values so tags are 0..N-1","Never cast raw ints to the enum type without range-checking","Add a unit test asserting every variant's numeric tag is within 0..count-1"],"tags":["csharp","spacetimedb","bsatn","serialization","enum"],"backgroundTag":"enum-tag-out-of-range","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"}