dotnet/aspnetcore · error · Error
Interop methods are already registered for renderer
Error message
Interop methods are already registered for renderer ${rendererId} What it means
Thrown by attachWebWidgetInterop when interopMethodsByRenderer already has an entry for the given rendererId. Each renderer should attach its interop bridge exactly once; a second attachment indicates a double-initialization bug. The map is keyed by rendererId, so the same id registering twice is the trigger.
Solutions
- Call detachWebRendererInterop(rendererId) before re-attaching for the same id.
- Ensure Blazor.start is invoked exactly once per page.
- Avoid sharing a rendererId across multiple renderer instances; let the framework allocate ids.
- In reconnect logic, follow the framework's detach->attach sequence rather than attach->attach.
Example fix
// before (throws on second call) attachWebRendererInterop(1, interop, params, inits); attachWebRendererInterop(1, interop2, params, inits); // after detachWebRendererInterop(1); attachWebRendererInterop(1, interop2, params, inits);
Defensive patterns
Strategy: validation
Validate before calling
if (interopMethodsByRenderer.has(rendererId)) {
// already attached — detach first if this is a legitimate re-attach
detachWebRendererInterop(rendererId);
}
attachWebRendererInterop(rendererId, interop, params, inits); Prevention
- Attach interop exactly once per rendererId.
- In reconnect scenarios, detach before re-attaching.
- Let the framework manage rendererIds; don't hard-code them.
When it happens
Trigger: Blazor.start being called twice; a circuit reconnect path that re-attaches without first detaching; two interactive renderers created with the same id; a misconfigured custom host that calls attachWebRendererInterop manually more than once.
Common situations: Hot reload re-running initialization; a custom hosting layer that manually drives Blazor lifecycle and calls attach twice; testing harness that doesn't tear down between runs.
Related errors
- Interop methods are not registered for renderer
- No interop methods are registered for renderer
- Renderer with ID ' ' is not listening for navigation events
- There is no file with ID
- Cannot update existing state: previous state has not been…
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/26b1d5b1841d75fb.
Report an issue: GitHub.
Appendix: 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 3600ca084e)