{"record":{"id":"26b1d5b1841d75fb","repo":"dotnet/aspnetcore","slug":"interop-methods-are-already-registered-for-rendere","errorCode":null,"errorMessage":"Interop methods are already registered for renderer ${rendererId}","messagePattern":"Interop methods are already registered for renderer (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Components/Web.JS/src/Rendering/WebRendererInteropMethods.ts","lineNumber":27,"sourceCode":"const rendererAttachedListeners: ((browserRendererId: number) => void)[] = [];\nconst rendererByIdResolverMap: Map<number, [() => void | undefined, Promise<void> | undefined]> = new Map();\n\nexport function attachRendererIdResolver(rendererId: number, resolver: () => void | undefined, promise: Promise<void> | undefined) {\n  rendererByIdResolverMap.set(rendererId, [resolver, promise]);\n}\n\nexport function getRendererAttachedPromise(rendererId: number): Promise<void> | undefined {\n  return rendererByIdResolverMap.get(rendererId)?.[1];\n}\n\nexport function attachWebRendererInterop(\n  rendererId: number,\n  interopMethods: DotNet.DotNetObject,\n  jsComponentParameters?: JSComponentParametersByIdentifier,\n  jsComponentInitializers?: JSComponentIdentifiersByInitializer,\n): void {\n  if (interopMethodsByRenderer.has(rendererId)) {\n    throw new Error(`Interop methods are already registered for renderer ${rendererId}`);\n  }\n\n  interopMethodsByRenderer.set(rendererId, interopMethods);\n\n  if (jsComponentParameters && jsComponentInitializers && Object.keys(jsComponentParameters).length > 0) {\n    const manager = getInteropMethods(rendererId);\n    enableJSRootComponents(rendererId, manager, jsComponentParameters, jsComponentInitializers);\n  }\n\n  rendererByIdResolverMap.get(rendererId)?.[0]?.();\n\n  invokeRendererAttachedListeners(rendererId);\n}\n\nexport function detachWebRendererInterop(rendererId: number): DotNet.DotNetObject {\n  const interopMethods = interopMethodsByRenderer.get(rendererId);\n  if (!interopMethods) {\n    throw new Error(`Interop methods are not registered for renderer ${rendererId}`);","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Web.JS/src/Rendering/WebRendererInteropMethods.ts#L9-L45","documentation":"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.","triggerScenarios":"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.","commonSituations":"Reconnection flows racing with attach; HMR re-initializing the renderer; calling Blazor.start() twice; custom hosts that re-attach on route change.","solutions":["Ensure detachWebRendererInterop runs (e.g. on connection close) before re-attaching — the framework does this in onclose.","Avoid calling Blazor.start() more than once; reload the page instead.","Guard custom attach code with isRendererAttached(rendererId) before calling attach."],"exampleFix":"// before\nattachWebRendererInterop(WebRendererId.Server, methods); // second attach throws\n\n// after\nif (!isRendererAttached(WebRendererId.Server)) {\n  attachWebRendererInterop(WebRendererId.Server, methods);\n}","handlingStrategy":"validation","validationCode":"// Guard attach with isRendererAttached.\nimport { attachWebRendererInterop, isRendererAttached } from './WebRendererInteropMethods';\nif (!isRendererAttached(WebRendererId.Server)) {\n  attachWebRendererInterop(WebRendererId.Server, methods);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always detach (detachWebRendererInterop) before re-attaching a renderer.","Call Blazor.start() only once; reload to reinitialize.","Guard custom attach paths with isRendererAttached()."],"tags":["blazor","renderer","interop","lifecycle"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}