{"record":{"id":"24d75550cf5587fc","repo":"clockworklabs/SpacetimeDB","slug":"invalid-row-type-for-table-remotetablename-old","errorCode":null,"errorMessage":"Invalid row type for table {RemoteTableName}: {oldValue.GetType().Name}","messagePattern":"Invalid row type for table (.+?): (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"sdks/csharp/src/Table.cs","lineNumber":531,"sourceCode":"            {\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                }\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,","sourceCodeStart":513,"sourceCodeEnd":549,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/9e0d92412ff2248f401a8ad12d535f2b5ac30912/sdks/csharp/src/Table.cs#L513-L549","documentation":"In the wasUpdated loop of Table.Apply, the OLD value for each updated key must be a Row so the internal delete handler can fire for it. This variant means the previously cached value (not the incoming one) is not a Row instance, i.e. the cache was populated with non-Row values at some earlier point. It indicates the same class of invariant break as the insert variant, but surfaces on the update path.","triggerScenarios":"A row update arrives for a table whose cache was earlier populated with non-Row values: custom table handle with a plain class as TValue, or mixed-version generated code where insert-variant checks were skipped (older SDK) and an update now hits the check.","commonSituations":"Partial upgrade: client assembly updated but some generated table files regenerated with an older toolchain; custom table implementations in test harnesses or fixtures.","solutions":["Regenerate all bindings with the CLI version matching the SDK package so every table's TValue is Row-derived.","Audit custom table/IRemoteTableHandle implementations and derive row types from Row.","If fully generated, report with the table name and delta - old cache values of non-Row type should be impossible."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"static bool IsRowType(Type t) => typeof(SpacetimeDB.Runtime.Row).IsAssignableFrom(t); // assert for all cached row types","tryCatchPattern":"conn.SubscriptionBuilder().OnError(ex => Log.Error($\"cached row invariant broken: {ex.Message}\"));","preventionTips":["Regenerate all bindings together with SDK upgrades - partial regeneration leaves non-Row cached values.","Do not persist or inject custom values into table caches."],"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"}