dotnet/aspnetcore · error · Error

Circuit options have already been configured.

Error message

Circuit options have already been configured.

What it means

Thrown by setCircuitOptions in Boot.Server.Common.ts if the module-level 'options' variable is already set. Circuit options are a singleton: they are configured once during boot and reused for the lifetime of the page. A second call means boot/initialization logic ran twice.

Source

Thrown at src/Components/Web.JS/src/Boot.Server.Common.ts:27

import { DefaultReconnectionHandler } from './Platform/Circuits/DefaultReconnectionHandler';
import { discoverServerPersistedState, ServerComponentDescriptor } from './Services/ComponentDescriptorDiscovery';
import { JSEventRegistry } from './Services/JSEventRegistry';
import { fetchAndInvokeInitializers } from './JSInitializers/JSInitializers.Server';
import { RootComponentManager } from './Services/RootComponentManager';
import { WebRendererId } from './Rendering/WebRendererId';
import { addDispatchEventMiddleware } from './Rendering/WebRendererInteropMethods';

let initializersPromise: Promise<void> | undefined;
let appState: string;
let circuit: CircuitManager;
let options: CircuitStartOptions;
let logger: ConsoleLogger;
let serverStartPromise: Promise<void>;
let circuitStarting: Promise<boolean> | undefined;

export function setCircuitOptions(initializersReady: Promise<Partial<CircuitStartOptions>>) {
  if (options) {
    throw new Error('Circuit options have already been configured.');
  }

  initializersPromise = setOptions(initializersReady);

  async function setOptions(initializers: Promise<Partial<CircuitStartOptions>>): Promise<void> {
    const configuredOptions = await initializers;
    options = resolveOptions(configuredOptions);
  }
}

export function startServer(components: RootComponentManager<ServerComponentDescriptor>, jsEventRegistry: JSEventRegistry): Promise<void> {
  if (serverStartPromise !== undefined) {
    throw new Error('Blazor Server has already started.');
  }

  serverStartPromise = new Promise(startServerCore.bind(null, components, jsEventRegistry));

  return serverStartPromise;

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Call Blazor.start() at most once; guard with if (!Blazor._internal.isStarted) or check hasStartedServer() before starting.
  2. Disable auto-start (do not include the autostart flag / set window.Blazor to disable) when you call start() manually.
  3. Ensure JS initializers only read options, not re-configure them; route all option changes through the single boot call.
  4. Remove duplicate <script> references to blazor.server.js / blazor.web.js.

Example fix

// before: double configuration
Blazor.start({ circuit: { ... } });
Blazor.start({ circuit: { ... } }); // throws

// after: start once
if (!window.__blazorStarted) {
  window.__blazorStarted = true;
  Blazor.start({ circuit: { ... } });
}
Defensive patterns

Strategy: validation

Validate before calling

// No public 'optionsConfigured' flag is exported; guard with a window flag.
function configureCircuitOnce(opts: Partial<CircuitStartOptions>) {
  if ((window as any).__circuitOptionsConfigured) return;
  (window as any).__circuitOptionsConfigured = true;
  Blazor.start({ circuit: opts });
}

Type guard

declare module './Boot.Server.Common' {
  function setCircuitOptions(p: Promise<Partial<CircuitStartOptions>>): void;
}
// call only when not yet started
function shouldConfigure(): boolean {
  return !(window as any).__circuitOptionsConfigured;
}

Try / catch

try {
  setCircuitOptions(initializersReady);
} catch (e) {
  if (/already been configured/.test((e as Error).message)) {
    // idempotent no-op
  } else throw e;
}

Prevention

When it happens

Trigger: Calling Blazor.start({ circuit: {...} }) more than once, or a JS initializer that also calls setCircuitOptions, or Boot.Web.ts's onInitialDomContentLoaded running twice (e.g. two DOMContentLoaded listeners or a double boot).

Common situations: Manually invoking Blazor.start() in script while auto-start is also enabled; an HMR/hot-reload cycle re-running the boot module; a custom hosting page that calls start() then re-imports the bundle; misconfigured initializers that mutate circuit options twice.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/527ca53ac2e2d946. Report an issue: GitHub.