{"record":{"id":"1b2a697bb5c027a3","repo":"clockworklabs/SpacetimeDB","slug":"invalid-row-type-for-table-remotetablename-new","errorCode":null,"errorMessage":"Invalid row type for table {RemoteTableName}: {newValue.GetType().Name}","messagePattern":"Invalid row type for table (.+?): (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"sdks/csharp/src/Table.cs","lineNumber":541,"sourceCode":"            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                }\n                else\n                {\n                    throw new Exception($\"Invalid row type for table {RemoteTableName}: {newValue.GetType().Name}\");\n                }\n            }\n        }\n\n        /// <summary>\n        /// Invoked after applying the parsed table update (delta) to this table.\n        /// This is when user callbacks (such as OnInsert, OnUpdate, and OnDelete) are actually triggered for the affected rows.\n        /// All <see cref=\"IRemoteTableHandle.Apply\"/> operations should be complete before calling PostApply,\n        /// so that data structures across all tables are fully updated before invoking user callbacks.\n        /// Should be called after PreApply and Apply.\n        /// </summary>\n        void IRemoteTableHandle.PostApply(IEventContext context)\n        {\n            foreach (var (_, value) in wasInserted)\n            {\n                InvokeInsert(context, value);\n            }\n            if (!IsEventTable)","sourceCodeStart":523,"sourceCodeEnd":559,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/9e0d92412ff2248f401a8ad12d535f2b5ac30912/sdks/csharp/src/Table.cs#L523-L559","documentation":"In the wasUpdated loop of Table.Apply, the NEW value for each updated key must be a Row so the internal insert handler can fire for it. This variant means the value produced for the post-update row is not a Row instance. It points at how updated values are materialized into the cache (row deserialization/type mapping), not at your reducer logic.","triggerScenarios":"An update delta materializes into a non-Row object: generated row type not deriving from Row (stale or hand-edited generated code), or a custom value factory used by the table implementation.","commonSituations":"Hand-edited generated bindings; SDK/package version skew between the runtime assembly and the generated table classes.","solutions":["Regenerate bindings so updated values are instances of the generated Row subclass.","Remove hand edits to generated files and derive any custom row types from SpacetimeDB.Runtime.Row.","If reproducible with clean generated code, file an SDK issue including the table name and update delta."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"static bool IsRowType(Type t) => typeof(SpacetimeDB.Runtime.Row).IsAssignableFrom(t);","tryCatchPattern":"conn.SubscriptionBuilder().OnError(ex => Log.Error($\"update row invariant broken: {ex.Message}\"));","preventionTips":["Keep generated files pristine; custom row types must derive Row.","Pin SDK and codegen versions together in CI."],"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"}