{"record":{"id":"baedc461d3927a6d","repo":"dotnet/aspnetcore","slug":"interop-methods-are-not-registered-for-renderer","errorCode":null,"errorMessage":"Interop methods are not registered for renderer ${rendererId}","messagePattern":"Interop methods are not registered for renderer (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/Components/Web.JS/src/Rendering/WebRendererInteropMethods.ts","lineNumber":45,"sourceCode":"    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}`);\n  }\n\n  interopMethodsByRenderer.delete(rendererId);\n  return interopMethods;\n}\n\nexport function isRendererAttached(browserRendererId: number): boolean {\n  return interopMethodsByRenderer.has(browserRendererId);\n}\n\nexport function registerRendererAttachedListener(listener: (browserRendererId: number) => void) {\n  rendererAttachedListeners.push(listener);\n}\n\nfunction invokeRendererAttachedListeners(browserRendererId: number) {\n  for (const listener of rendererAttachedListeners) {\n    listener(browserRendererId);\n  }","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Web.JS/src/Rendering/WebRendererInteropMethods.ts#L27-L63","documentation":"Thrown by detachWebRendererInterop when no interop methods are registered for the given rendererId. Detach assumes the renderer was previously attached; calling it on an unknown id signals teardown ordering is wrong or detach was called twice. The method deletes the entry and returns the captured DotNetObjectReference.","triggerScenarios":"Calling detachWebRendererInterop for a rendererId that was never attached; calling detach twice (the first removes the entry, the second throws); tearing down after a failed attach.","commonSituations":"Error-handling/cleanup path that calls detach unconditionally; reconnect logic that detaches before attach completed; double-dispose of a renderer.","solutions":["Guard detach with a check using isRendererAttached(rendererId) before calling.","Track attach state and only detach when you previously attached.","Avoid calling detach in a finally block unless you know attach succeeded.","Use try/catch around detach if it is best-effort cleanup."],"exampleFix":"// before (throws if never attached)\ndetachWebRendererInterop(rendererId);\n\n// after\nif (isRendererAttached(rendererId)) {\n  detachWebRendererInterop(rendererId);\n}","handlingStrategy":"type-guard","validationCode":"if (isRendererAttached(rendererId)) {\n  detachWebRendererInterop(rendererId);\n} else {\n  // nothing to detach — no-op or log\n}","typeGuard":"function canDetach(rendererId: number): boolean {\n  return isRendererAttached(rendererId);\n}","tryCatchPattern":"try { detachWebRendererInterop(rendererId); }\ncatch (e) {\n  if (/not registered/.test(String(e?.message))) { /* benign double-detach */ }\n  else { throw e; }\n}","preventionTips":["Track attach state and only detach what you attached.","Guard cleanup paths with isRendererAttached.","Avoid unconditional detach in finally blocks."],"tags":["blazor","interop","renderer","lifecycle","cleanup"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}