clockworklabs/SpacetimeDB · error · InvalidOperationException

Identity not set

Error message

Identity not set

What it means

DbConnection.Identity is assigned only when the InitialConnection message is processed (which also fires onConnect). The ProcedureResult branch builds a ProcedureEvent with Identity ?? throw, so a result arriving before identity is established throws on the parse thread; the parse loop then logs it and disconnects. Connect() resets Identity to null, so stale queued results after a reconnect can also trip it.

Source

Thrown at sdks/csharp/src/SpacetimeDBClient.cs:562

                                    pendingReducer.Reducer);
                            }
                            catch (Exception)
                            {
                                // The local reducer request still completed; failure here should not block update apply.
                            }
                        }
                        else
                        {
                            throw new InvalidOperationException(
                                $"Reducer result for unknown request_id {reducerResult.RequestId}"
                            );
                        }
                        break;
                    case ServerMessage.ProcedureResult(var procedureResult):
                        procedureEvent = new ProcedureEvent(
                            procedureResult.Timestamp,
                            procedureResult.Status,
                            Identity ?? throw new InvalidOperationException("Identity not set"),
                            ConnectionId,
                            procedureResult.TotalHostExecutionDuration,
                            procedureResult.RequestId
                        );

                        if (!stats.ProcedureRequestTracker.FinishTrackingRequest(procedureResult.RequestId, unparsed.timestamp))
                        {
                            Log.Warn($"Failed to finish tracking procedure request: {procedureResult.RequestId}");
                        }

                        break;
                    default:
                        throw new InvalidOperationException();
                }

                stats.ParseMessageTracker.InsertRequest(parseStart, trackerMetadata);
                var applyTracker = stats.ApplyMessageQueueTracker.StartTrackingRequest(trackerMetadata);

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Gate all procedure/reducer calls behind the OnConnect callback — identity is set before onConnect fires
  2. After any reconnect, use a newly built connection instead of racing the old one's message queues
  3. If ordering still looks wrong on current versions, report it with the message timeline

Example fix

// before
var conn = builder.Build();
conn.RemotelyCallProcedure(...); // Identity may still be null

// after
var conn = builder
    .OnConnect((c, identity, token) => c.RemotelyCallProcedure(...))
    .Build();
Defensive patterns

Strategy: validation

Validate before calling

// Gate calls on connection readiness — Identity is public on DbConnection:
if (conn.Identity is null)
{
    Log.Warn("Connection not initialized yet; deferring call until OnConnect");
    return;
}

Type guard

static bool IsSessionEstablished(DbConnection conn) => conn.Identity is not null;

Prevention

When it happens

Trigger: Invoking procedures (or receiving their results) before OnConnect has fired; a reconnect race where Identity was reset but old messages are still in the parse queue; server message-ordering violations.

Common situations: Calling procedures immediately after Build() in a loop instead of inside the OnConnect callback; aggressive reconnect logic reusing connection state.

Related errors


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