clockworklabs/SpacetimeDB · critical · InvalidOperationException

Called NonValueChange on a ValueDelta in an ambiguous state:

Error message

Called NonValueChange on a ValueDelta in an ambiguous state: {this}

What it means

The client-side cache for MultiDictionary tables accumulates signed multiplicity deltas per key, holding at most two distinct values (D1/D2). NonValueChange requires exactly one of them to have a zero delta; when both are zero or both are non-zero with the same sign, the invariant is broken. The code comment explicitly calls this a server-side error and throws — it is not an application-logic failure.

Source

Thrown at sdks/csharp/src/MultiDictionary.cs:509

                    else
                    {
                        // Now we're in a weird place.
                        // We're not an update, but D2 is initialized.
                        // This means that at least one of D1 or D2 has Delta == 0.
                        // If exactly one of them has Delta == 0, we're okay:
                        if (D1.Delta == 0 && D2.Value.Delta != 0)
                        {
                            return D2.Value;
                        }
                        else if (D1.Delta != 0 && D2.Value.Delta == 0)
                        {
                            return D1;
                        }
                        else
                        {
                            // In this case, something strange is going on: both values have the same sign.
                            // There's nothing sensible to do here, and this represents a server-side error, so just throw.
                            throw new InvalidOperationException($"Called NonValueChange on a ValueDelta in an ambiguous state: {this}");
                        }
                    }
                }
            }

            /// <summary>
            /// Add a copy of this Value to this KeyDelta.
            /// </summary>
            /// <param name="value"></param>
            /// <param name="equalityComparer"></param>
            public void Add(TValue value, IEqualityComparer<TValue> equalityComparer)
            {
                if (equalityComparer.Equals(value, D1.Value))
                {
                    D1.Delta += 1;
                }
                else if (D2 == null)
                {

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Update the C# SDK and the SpacetimeDB server to matching released versions
  2. If you pass a custom IEqualityComparer<TValue> to MultiDictionary, verify it is a proper, stable equality (consistent with value equality the server observes)
  3. Reconnect and resubscribe to rebuild the client cache from a clean snapshot
  4. Capture the exception plus the reducer/transaction context and file a SpacetimeDB bug — the source marks this as a server error
Defensive patterns

Strategy: try-catch

Try / catch

// Around the code that drives FrameTick / message processing in non-Unity hosts:
try { conn.FrameTick(); }
catch (InvalidOperationException e) when (e.Message.Contains("ambiguous state"))
{ /* client/server cache desync: disconnect, rebuild the connection, resubscribe */ }

Prevention

When it happens

Trigger: Applying subscription/transaction updates to a table stored in a MultiDictionary when the server diff for one key degenerates into an ambiguous two-value state. Typically coincides with SDK/server version mismatch or a server diff-generation bug; an inconsistent custom IEqualityComparer<TValue> can also collapse distinct values incorrectly.

Common situations: Client cache updates after a long-lived subscription on SDK and server versions that drifted apart; custom equality comparers on the value type; reproduces consistently on the same reducer/transaction.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16). Data as JSON: /api/errors/1046082f3c13f2cc. Report an issue: GitHub.