{"record":{"id":"43546a78b03dda57","repo":"dotnet/aspnetcore","slug":"blazor-server-has-already-started","errorCode":null,"errorMessage":"Blazor Server has already started.","messagePattern":"Blazor Server has already started\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Components/Web.JS/src/Boot.Server.Common.ts","lineNumber":40,"sourceCode":"let serverStartPromise: Promise<void>;\nlet circuitStarting: Promise<boolean> | undefined;\n\nexport function setCircuitOptions(initializersReady: Promise<Partial<CircuitStartOptions>>) {\n  if (options) {\n    throw new Error('Circuit options have already been configured.');\n  }\n\n  initializersPromise = setOptions(initializersReady);\n\n  async function setOptions(initializers: Promise<Partial<CircuitStartOptions>>): Promise<void> {\n    const configuredOptions = await initializers;\n    options = resolveOptions(configuredOptions);\n  }\n}\n\nexport function startServer(components: RootComponentManager<ServerComponentDescriptor>, jsEventRegistry: JSEventRegistry): Promise<void> {\n  if (serverStartPromise !== undefined) {\n    throw new Error('Blazor Server has already started.');\n  }\n\n  serverStartPromise = new Promise(startServerCore.bind(null, components, jsEventRegistry));\n\n  return serverStartPromise;\n}\n\nasync function startServerCore(components: RootComponentManager<ServerComponentDescriptor>, jsEventRegistry: JSEventRegistry, resolve: () => void, _: any) {\n  await initializersPromise;\n  const jsInitializer = await fetchAndInvokeInitializers(options);\n\n  appState = discoverServerPersistedState(document) || '';\n  logger = new ConsoleLogger(options.logLevel);\n  circuit = new CircuitManager(components, appState, options, logger, jsEventRegistry);\n\n  addDispatchEventMiddleware((_browserRendererId, eventHandlerId, continuation) => {\n    logger.log(LogLevel.Debug, `Dispatching event with handler id ${eventHandlerId}.`);\n    continuation();","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Web.JS/src/Boot.Server.Common.ts#L22-L58","documentation":"Thrown by startServer in Boot.Server.Common when the module-level serverStartPromise is already defined. startServer is the single entrypoint for bringing up the SignalR circuit client; invoking it again indicates Blazor Server has been booted twice and the second invocation is rejected to preserve a single circuit lifecycle.","triggerScenarios":"Calling the server boot path (directly or via Blazor.start for Server) twice in one page, or framework code re-entering startServer after a successful start.","commonSituations":"Manual Blazor.start() combined with autostart; hot-reload/HMR re-evaluating the boot module; a micro-frontend shell that mounts two Blazor Server apps via the same boot entrypoint; misrouted imports causing Boot.Server to load twice.","solutions":["Call startServer (or Blazor.start in Server mode) exactly once per page.","Guard the call site with a module-level flag and a memoized promise so re-entry is a no-op.","If running multiple Blazor Server apps, use a single boot and multiple root components rather than multiple boots.","Confirm autostart is disabled when you start manually."],"exampleFix":"// before\nasync function ensureBlazor() {\n  await Blazor.start(); // throws on second call\n}\n\n// after\nlet bootPromise;\nfunction ensureBlazor() {\n  return bootPromise ?? (bootPromise = Blazor.start());\n}","handlingStrategy":"validation","validationCode":"// Memoize start so startServer is entered exactly once.\nlet serverPromise;\nfunction startBlazorServerOnce() {\n  return serverPromise ?? (serverPromise = Blazor.start());\n}","typeGuard":null,"tryCatchPattern":"try {\n  await Blazor.start();\n} catch (e) {\n  if (/already started/.test(e.message)) return; // idempotent\n  throw e;\n}","preventionTips":["Boot Server exactly once per page.","Disable autostart when starting manually.","Centralize boot in a single module.","Do not reuse the boot path across micro-frontends; use multiple root components instead."],"tags":["blazor-server","boot","lifecycle","double-start"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}