{"record":{"id":"047e050fb0039a14","repo":"angular/components","slug":"this-portaloutlet-has-already-been-disposed","errorCode":null,"errorMessage":"This PortalOutlet has already been disposed","messagePattern":"This PortalOutlet has already been disposed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cdk/portal/portal-errors.ts","lineNumber":30,"sourceCode":" */\nexport function throwNullPortalError() {\n  throw Error('Must provide a portal to attach');\n}\n\n/**\n * Throws an exception when attempting to attach a portal to a host that is already attached.\n * @docs-private\n */\nexport function throwPortalAlreadyAttachedError() {\n  throw Error('Host already has a portal attached');\n}\n\n/**\n * Throws an exception when attempting to attach a portal to an already-disposed host.\n * @docs-private\n */\nexport function throwPortalOutletAlreadyDisposedError() {\n  throw Error('This PortalOutlet has already been disposed');\n}\n\n/**\n * Throws an exception when attempting to attach an unknown portal type.\n * @docs-private\n */\nexport function throwUnknownPortalTypeError() {\n  throw Error(\n    'Attempting to attach an unknown Portal type. BasePortalOutlet accepts either ' +\n      'a ComponentPortal or a TemplatePortal.',\n  );\n}\n\n/**\n * Throws an exception when attempting to attach a portal to a null host.\n * @docs-private\n */\nexport function throwNullPortalOutletError() {","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/portal/portal-errors.ts#L12-L48","documentation":"`throwPortalOutletAlreadyDisposedError` fires when `attach` is called on an outlet whose `dispose()` has already run. A disposed outlet has torn down its resources and can never host a portal again; a new outlet instance is required.","triggerScenarios":"Calling `attach` on a DomPortalOutlet after `outlet.dispose()`; using a cached/stored outlet reference after its host was destroyed; attaching a portal in a component whose outlet was disposed during teardown (e.g. after NavigationEnd cleanup).","commonSituations":"Long-lived services caching outlets for destroyed overlays; async callbacks (HTTP, timers) resolving after dispose; HMR or route changes disposing outlets while pending attaches are in flight.","solutions":["Create a new outlet instance after dispose instead of reusing it","Guard with a disposed flag/`isDisposed` check before attach","Cancel pending async work (takeUntilDestroyed, unsubscribe) so attach never runs post-dispose","Move outlet creation/dispose into the same component lifecycle as the attach logic"],"exampleFix":"// before\nthis.outlet.dispose();\nthis.outlet.attach(portal); // throws\n// after\nthis.outlet.dispose();\nthis.outlet = new DomPortalOutlet(hostEl, injector, appRef, document);\nthis.outlet.attach(portal);","handlingStrategy":"try-catch","validationCode":"if (!disposed) outlet.attach(portal);","typeGuard":null,"tryCatchPattern":"try { outlet.attach(portal); } catch (e) { if (String(e.message).includes('already been disposed')) { outlet = createOutlet(); outlet.attach(portal); } else { throw e; } }","preventionTips":["Null cached outlets on dispose","Cancel async attaches on teardown","Rebuild outlets after dispose"],"tags":["angular","cdk","portal","lifecycle"],"backgroundTag":"portal-outlet-disposed","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}