{"record":{"id":"c0995e59ea6b760c","repo":"clockworklabs/SpacetimeDB","slug":"invalid-row-type-for-table-remotetablename-val","errorCode":null,"errorMessage":"Invalid row type for table {RemoteTableName}: {value.GetType().Name}","messagePattern":"Invalid row type for table (.+?): (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"sdks/csharp/src/Table.cs","lineNumber":520,"sourceCode":"            // (And we need to do it before any PostApply is called.)\n            // Reminder: We need to loop through the removed entries to delete them prior to inserting the new entries,\n            // in order to avoid keys an error with the same key already added.\n            foreach (var (_, value) in wasRemoved)\n            {\n                if (value is Row oldRow)\n                {\n                    OnInternalDeleteHandler.Invoke(oldRow);\n                }\n            }\n            foreach (var (_, value) in wasInserted)\n            {\n                if (value is Row newRow)\n                {\n                    OnInternalInsertHandler.Invoke(newRow);\n                }\n                else\n                {\n                    throw new Exception($\"Invalid row type for table {RemoteTableName}: {value.GetType().Name}\");\n                }\n            }\n            foreach (var (_, oldValue, newValue) in wasUpdated)\n            {\n                if (oldValue is Row oldRow)\n                {\n                    OnInternalDeleteHandler.Invoke(oldRow);\n                }\n                else\n                {\n                    throw new Exception($\"Invalid row type for table {RemoteTableName}: {oldValue.GetType().Name}\");\n                }\n\n\n                if (newValue is Row newRow)\n                {\n                    OnInternalInsertHandler.Invoke(newRow);\n                }","sourceCodeStart":502,"sourceCodeEnd":538,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/9e0d92412ff2248f401a8ad12d535f2b5ac30912/sdks/csharp/src/Table.cs#L502-L538","documentation":"After applying a delta, Table.Apply walks the wasInserted list and invokes the internal insert handler for each value, requiring every value in the table's row cache to be an instance of SpacetimeDB.Runtime.Row. This exception means a newly inserted cache value has some other type, breaking the SDK's internal invariant. It is not triggered by bad row data, only by a wrong value type in the cache.","triggerScenarios":"The table's cache value type is not a Row-derived class: hand-written table handles or a custom IRemoteTableHandle implementation, or generated bindings from an SDK generation that used non-Row row types paired with a newer SDK runtime.","commonSituations":"Upgrading the SpacetimeDB C# SDK major version while keeping bindings generated by an older CLI; implementing a custom table abstraction instead of using generated table handles.","solutions":["Regenerate all bindings with the spacetimedb CLI version that matches the installed SDK package.","If you wrote the table type by hand, make the row type derive from SpacetimeDB.Runtime.Row like generated row classes do.","If everything is generated and versions match, capture the delta/table name and file an SDK issue - the invariant should hold."],"exampleFix":"// before: hand-written table with a plain POCO row type\nclass PlayerRow { public ulong Id; }\n\n// after: row types must derive from Row (as generated code does)\nusing SpacetimeDB.Runtime;\nclass PlayerRow : Row { public ulong Id; }","handlingStrategy":"type-guard","validationCode":"foreach (var t in typeof(Program).Assembly.GetTypes())\n{\n    if (t.GetCustomAttributes().Any(a => a.GetType().Name == \"TableAttribute\"))\n    {\n        // row types used by table handles must be Row subclasses\n    }\n}","typeGuard":"static bool IsRowType(Type t) => typeof(SpacetimeDB.Runtime.Row).IsAssignableFrom(t);","tryCatchPattern":"conn.SubscriptionBuilder().OnError(ex => Log.Error($\"row invariant broken: {ex.Message}\"));","preventionTips":["Always generate table/row types with the CLI matching your SDK version.","In custom table code, derive row types from SpacetimeDB.Runtime.Row.","Treat this exception as a bug report signal - do not swallow it."],"tags":["csharp","sdk","internal-invariant","row-type"],"backgroundTag":"type-mismatch","analyzedSha":"9e0d92412ff2248f401a8ad12d535f2b5ac30912","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}