{"record":{"id":"4fa762bf46f52514","repo":"dotnet/aspnetcore","slug":"circuit-host-not-initialized","errorCode":null,"errorMessage":"Circuit host not initialized.","messagePattern":"Circuit host not initialized\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/Components/Web.JS/src/Platform/Circuits/CircuitManager.ts","lineNumber":166,"sourceCode":"    connection.on('JS.AttachComponent', (componentId, selector) => attachRootComponentToLogicalElement(WebRendererId.Server, this.resolveElement(selector), componentId, false));\n    connection.on('JS.BeginInvokeJS', (asyncHandle: number, ...rest: unknown[]) => {\n      if (asyncHandle !== 0) {\n        this.changeActivity(1);\n      }\n      (this._dispatcher.beginInvokeJSFromDotNet as (...a: unknown[]) => unknown)\n        .call(this._dispatcher, asyncHandle, ...rest);\n    });\n    connection.on('JS.EndInvokeDotNet', (asyncCallId: string, success: boolean, resultJsonOrExceptionMessage: string) => {\n      if (asyncCallId) {\n        this.changeActivity(-1);\n      }\n      this._dispatcher.endInvokeDotNetFromJS(asyncCallId, success, resultJsonOrExceptionMessage);\n    });\n    connection.on('JS.ReceiveByteArray', this._dispatcher.receiveByteArray.bind(this._dispatcher));\n\n    connection.on('JS.SavePersistedState', (circuitId: string, components: string, applicationState: string) => {\n      if (!this._circuitId) {\n        throw new Error('Circuit host not initialized.');\n      }\n      if (circuitId !== this._circuitId) {\n        throw new Error(`Received persisted state for circuit ID '${circuitId}', but the current circuit ID is '${this._circuitId}'.`);\n      }\n      this._persistedCircuitState = { components, applicationState };\n      return true;\n    });\n\n    connection.on('JS.BeginTransmitStream', (streamId: number) => {\n      const readableStream = new ReadableStream({\n        start: (controller) => {\n          this.changeActivity(1);\n          connection.stream('SendDotNetStreamToJS', streamId).subscribe({\n            next: (chunk: Uint8Array) => controller.enqueue(chunk),\n            complete: () => { controller.close(); this.changeActivity(-1); },\n            error: (err) => { controller.error(err); this.changeActivity(-1); },\n          });\n        },","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Web.JS/src/Platform/Circuits/CircuitManager.ts#L148-L184","documentation":"The `JS.SavePersistedState` SignalR handler receives persisted component/application state from the server (used when a circuit is paused/resumed). It requires a live circuit id (`_circuitId`) to attach the state to; if `_circuitId` is undefined the message arrived before `startCore` assigned one (or after it was cleared), so the handler refuses to record state for an unknown circuit.","triggerScenarios":"Server sends `JS.SavePersistedState` before `StartCircuit` returned a non-empty `_circuitId`, or the message is processed on a connection whose `startCore` returned falsy (no circuit established) but the server still pushed state.","commonSituations":"Race between an early persisted-state push and circuit start on slow/reconnecting links; server-side state preservation firing during a reconnect window where the client hasn't reconfirmed its circuit id; misordered SignalR messages during circuit pause/resume flows; dev-time hot reload reinitializing the manager.","solutions":["Ensure `Blazor.start()` has fully resolved (circuit started) before triggering flows that persist state (pause/resume, navigations that force state save).","Check server logs for why `StartCircuit` may have returned an empty id (server refusing circuit creation) and resolve the root cause.","On reconnect, let the framework re-run its start sequence rather than manually re-sending state messages.","Verify you are on a supported Blazor version — the persisted-state/pause-resume feature requires matching client and server builds."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// internal handler guard pattern\nif (!this._circuitId) { this._logger.log(LogLevel.Warning, 'Persisted state received before circuit started.'); return; }","typeGuard":null,"tryCatchPattern":"try { /* persisted-state handling */ }\ncatch (e) { if (/not initialized/.test(e.message)) { /* ignore stale state push */ return; } throw e; }","preventionTips":["Let Blazor.start() fully resolve before triggering state-persisting flows.","Keep client and server builds matched for the pause/resume feature.","Investigate empty StartCircuit ids in server logs.","Avoid manually sending persisted-state messages."],"tags":["circuit","persisted-state","signalr","lifecycle","blazor-server"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}