clockworklabs/SpacetimeDB · error · Exception
Invalid row type for table {RemoteTableName}: {newValue.GetT
Error message
Invalid row type for table {RemoteTableName}: {newValue.GetType().Name} What it means
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.
Source
Thrown at sdks/csharp/src/Table.cs:541
foreach (var (_, oldValue, newValue) in wasUpdated)
{
if (oldValue is Row oldRow)
{
OnInternalDeleteHandler.Invoke(oldRow);
}
else
{
throw new Exception($"Invalid row type for table {RemoteTableName}: {oldValue.GetType().Name}");
}
if (newValue is Row newRow)
{
OnInternalInsertHandler.Invoke(newRow);
}
else
{
throw new Exception($"Invalid row type for table {RemoteTableName}: {newValue.GetType().Name}");
}
}
}
/// <summary>
/// Invoked after applying the parsed table update (delta) to this table.
/// This is when user callbacks (such as OnInsert, OnUpdate, and OnDelete) are actually triggered for the affected rows.
/// All <see cref="IRemoteTableHandle.Apply"/> operations should be complete before calling PostApply,
/// so that data structures across all tables are fully updated before invoking user callbacks.
/// Should be called after PreApply and Apply.
/// </summary>
void IRemoteTableHandle.PostApply(IEventContext context)
{
foreach (var (_, value) in wasInserted)
{
InvokeInsert(context, value);
}
if (!IsEventTable)View on GitHub (pinned to 9e0d92412f)
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.
Defensive patterns
Strategy: type-guard
Type guard
static bool IsRowType(Type t) => typeof(SpacetimeDB.Runtime.Row).IsAssignableFrom(t);
Try / catch
conn.SubscriptionBuilder().OnError(ex => Log.Error($"update row invariant broken: {ex.Message}")); Prevention
- Keep generated files pristine; custom row types must derive Row.
- Pin SDK and codegen versions together in CI.
When it happens
Trigger: 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.
Common situations: Hand-edited generated bindings; SDK/package version skew between the runtime assembly and the generated table classes.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Invalid row type for table {RemoteTableName}: {value.GetType
- Invalid row type for table {RemoteTableName}: {oldValue.GetT
- Unsupported .NET SDK version: {major}. SpacetimeDB requires
- Token not initialized. Call AuthToken.Init() first.
- While table `{RemoteTableName}` was applying: {deltaString}
AI-assisted analysis of clockworklabs/SpacetimeDB@9e0d92412f (2026-08-20).
Data as JSON: /api/errors/1b2a697bb5c027a3.
Report an issue: GitHub.