dotnet/aspnetcore · error · Error

Dynamic root components have already been enabled.

Error message

Dynamic root components have already been enabled.

What it means

Thrown by enableJSRootComponents when a manager is already registered for a different rendererId. Dynamic JS root components are tied to a single renderer type (Server or WebAssembly); enabling them from a second, different renderer in the same page is a multi-host scenario the framework does not support.

Source

Thrown at src/Components/Web.JS/src/Rendering/JSRootComponents.ts:129

      for (const jsEventCallbackWrapper of this._jsEventCallbackWrappers.values()) {
        jsEventCallbackWrapper.dispose();
      }
    }
  }
}

// Called by the framework
export function enableJSRootComponents(
  rendererId: number,
  managerInstance: DotNet.DotNetObject,
  jsComponentParameters: JSComponentParametersByIdentifier,
  jsComponentInitializers: JSComponentIdentifiersByInitializer
): void {
  if (manager && currentRendererId !== rendererId) {
    // A different renderer type (e.g., Server vs WebAssembly) is trying to enable JS root components.
    // This is a multi-host scenario which is not supported for dynamic root components.
    throw new Error('Dynamic root components have already been enabled.');
  }

  // When the same renderer type re-enables (e.g., circuit restart or new circuit on same page),
  // accept the new manager. The old manager's DotNetObjectReference is no longer valid anyway
  // because the old circuit is gone. We don't dispose the old manager - doing so would cause
  // JSDisconnectedException because the circuit that created it no longer exists.
  currentRendererId = rendererId;
  manager = managerInstance;
  jsComponentParametersByIdentifier = jsComponentParameters;

  if (!hasInitializedJsComponents) {
    // Call the registered initializers. This is an arbitrary subset of the JS component types that are registered
    // on the .NET side - just those of them that require some JS-side initialization (e.g., to register them
    // as custom elements).
    for (const [initializerIdentifier, componentIdentifiers] of Object.entries(jsComponentInitializers)) {
      const initializerFunc = DotNet.findJSFunction(initializerIdentifier, 0) as JSComponentInitializerCallback;
      for (const componentIdentifier of componentIdentifiers) {
        const parameters = jsComponentParameters[componentIdentifier];

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Use only one renderer type per page for JS dynamic root components.
  2. Fix @rendermode configuration so a single renderer owns root components.
  3. If you genuinely need both, split across separate pages/iframes rather than one document.
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: A single page hosting both a Blazor Server and a Blazor WebAssembly root (InteractiveAuto misconfigured, or two Blazor roots of different kinds) where both try to register JS root components.

Common situations: Blazor Web App with mixed/incorrect rendermode wiring causing both Server and WebAssembly renderers to initialize JS root components; manually booting a second Blazor instance of a different kind on one page.

Related errors


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