dotnet/aspnetcore · error

Interop methods are already registered for renderer ${render

Error message

Interop methods are already registered for renderer ${rendererId}

What it means

Thrown by attachWebRendererInterop when interopMethodsByRenderer already has an entry for the given rendererId. Each renderer (Server=1, WebAssembly=2) may register its interop methods exactly once; a duplicate attach indicates the renderer initialized twice without a corresponding detach.

Source

Thrown at src/Components/Web.JS/src/Rendering/WebRendererInteropMethods.ts:27

const rendererAttachedListeners: ((browserRendererId: number) => void)[] = [];
const rendererByIdResolverMap: Map<number, [() => void | undefined, Promise<void> | undefined]> = new Map();

export function attachRendererIdResolver(rendererId: number, resolver: () => void | undefined, promise: Promise<void> | undefined) {
  rendererByIdResolverMap.set(rendererId, [resolver, promise]);
}

export function getRendererAttachedPromise(rendererId: number): Promise<void> | undefined {
  return rendererByIdResolverMap.get(rendererId)?.[1];
}

export function attachWebRendererInterop(
  rendererId: number,
  interopMethods: DotNet.DotNetObject,
  jsComponentParameters?: JSComponentParametersByIdentifier,
  jsComponentInitializers?: JSComponentIdentifiersByInitializer,
): void {
  if (interopMethodsByRenderer.has(rendererId)) {
    throw new Error(`Interop methods are already registered for renderer ${rendererId}`);
  }

  interopMethodsByRenderer.set(rendererId, interopMethods);

  if (jsComponentParameters && jsComponentInitializers && Object.keys(jsComponentParameters).length > 0) {
    const manager = getInteropMethods(rendererId);
    enableJSRootComponents(rendererId, manager, jsComponentParameters, jsComponentInitializers);
  }

  rendererByIdResolverMap.get(rendererId)?.[0]?.();

  invokeRendererAttachedListeners(rendererId);
}

export function detachWebRendererInterop(rendererId: number): DotNet.DotNetObject {
  const interopMethods = interopMethodsByRenderer.get(rendererId);
  if (!interopMethods) {
    throw new Error(`Interop methods are not registered for renderer ${rendererId}`);

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Ensure detachWebRendererInterop runs (e.g. on connection close) before re-attaching — the framework does this in onclose.
  2. Avoid calling Blazor.start() more than once; reload the page instead.
  3. Guard custom attach code with isRendererAttached(rendererId) before calling attach.

Example fix

// before
attachWebRendererInterop(WebRendererId.Server, methods); // second attach throws

// after
if (!isRendererAttached(WebRendererId.Server)) {
  attachWebRendererInterop(WebRendererId.Server, methods);
}
Defensive patterns

Strategy: validation

Validate before calling

// Guard attach with isRendererAttached.
import { attachWebRendererInterop, isRendererAttached } from './WebRendererInteropMethods';
if (!isRendererAttached(WebRendererId.Server)) {
  attachWebRendererInterop(WebRendererId.Server, methods);
}

Prevention

When it happens

Trigger: attachWebRendererInterop called twice for the same WebRendererId without an intervening detachWebRendererInterop — e.g. a circuit restart that re-attaches before the previous attach was detached, or double Blazor boot.

Common situations: Reconnection flows racing with attach; HMR re-initializing the renderer; calling Blazor.start() twice; custom hosts that re-attach on route change.

Related errors


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