{"record":{"id":"f484aaaf5d95a646","repo":"clockworklabs/SpacetimeDB","slug":"identity-not-set","errorCode":null,"errorMessage":"Identity not set","messagePattern":"Identity not set","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sdks/csharp/src/SpacetimeDBClient.cs","lineNumber":562,"sourceCode":"                                    pendingReducer.Reducer);\n                            }\n                            catch (Exception)\n                            {\n                                // The local reducer request still completed; failure here should not block update apply.\n                            }\n                        }\n                        else\n                        {\n                            throw new InvalidOperationException(\n                                $\"Reducer result for unknown request_id {reducerResult.RequestId}\"\n                            );\n                        }\n                        break;\n                    case ServerMessage.ProcedureResult(var procedureResult):\n                        procedureEvent = new ProcedureEvent(\n                            procedureResult.Timestamp,\n                            procedureResult.Status,\n                            Identity ?? throw new InvalidOperationException(\"Identity not set\"),\n                            ConnectionId,\n                            procedureResult.TotalHostExecutionDuration,\n                            procedureResult.RequestId\n                        );\n\n                        if (!stats.ProcedureRequestTracker.FinishTrackingRequest(procedureResult.RequestId, unparsed.timestamp))\n                        {\n                            Log.Warn($\"Failed to finish tracking procedure request: {procedureResult.RequestId}\");\n                        }\n\n                        break;\n                    default:\n                        throw new InvalidOperationException();\n                }\n\n                stats.ParseMessageTracker.InsertRequest(parseStart, trackerMetadata);\n                var applyTracker = stats.ApplyMessageQueueTracker.StartTrackingRequest(trackerMetadata);\n","sourceCodeStart":544,"sourceCodeEnd":580,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/sdks/csharp/src/SpacetimeDBClient.cs#L544-L580","documentation":"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.","triggerScenarios":"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.","commonSituations":"Calling procedures immediately after Build() in a loop instead of inside the OnConnect callback; aggressive reconnect logic reusing connection state.","solutions":["Gate all procedure/reducer calls behind the OnConnect callback — identity is set before onConnect fires","After any reconnect, use a newly built connection instead of racing the old one's message queues","If ordering still looks wrong on current versions, report it with the message timeline"],"exampleFix":"// before\nvar conn = builder.Build();\nconn.RemotelyCallProcedure(...); // Identity may still be null\n\n// after\nvar conn = builder\n    .OnConnect((c, identity, token) => c.RemotelyCallProcedure(...))\n    .Build();","handlingStrategy":"validation","validationCode":"// Gate calls on connection readiness — Identity is public on DbConnection:\nif (conn.Identity is null)\n{\n    Log.Warn(\"Connection not initialized yet; deferring call until OnConnect\");\n    return;\n}","typeGuard":"static bool IsSessionEstablished(DbConnection conn) => conn.Identity is not null;","tryCatchPattern":null,"preventionTips":["Start procedures/reducers from the OnConnect callback, never right after Build()","After reconnects, use a newly built connection so stale queue state cannot race identity assignment"],"tags":["connection-lifecycle","identity","procedures","csharp"],"backgroundTag":"connection-not-initialized","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}