angular/components · error
Attempting to detach a portal that is not attached to a host
Error message
Attempting to detach a portal that is not attached to a host
What it means
Thrown when detach() is called on a Portal that is not currently attached to any host. The Portal API tracks attachment state and refuses to detach something that was never attached (or was already detached), because there is no host view to remove it from.
Source
Thrown at src/cdk/portal/portal-errors.ts:57
'Attempting to attach an unknown Portal type. BasePortalOutlet accepts either ' +
'a ComponentPortal or a TemplatePortal.',
);
}
/**
* Throws an exception when attempting to attach a portal to a null host.
* @docs-private
*/
export function throwNullPortalOutletError() {
throw Error('Attempting to attach a portal to a null PortalOutlet');
}
/**
* Throws an exception when attempting to detach a portal that is not attached.
* @docs-private
*/
export function throwNoPortalAttachedError() {
throw Error('Attempting to detach a portal that is not attached to a host');
}
View on GitHub (pinned to 0411926e7d)
Solutions
- Check attachment state first: only call detach() if the portal is attached (e.g. wrap in try/catch or track attached outlet yourself)
- Guard cleanup with an attached flag: if (this.attached) { portal.detach(); this.attached = false; }
- Use the outlet's detach() (DomPortalOutlet.detach / CdkPortalOutlet.detach) only after verifying it has an attached portal (outlet.hasAttached())
- If using CdkPortalOutlet directive, prefer relying on its automatic cleanup on destroy instead of manual detach
Example fix
// before
ngOnDestroy() {
this.portal.detach(); // throws if never attached
}
// after
ngOnDestroy() {
if (this.outlet && this.outlet.hasAttached()) {
this.portal.detach();
}
} Defensive patterns
Strategy: validation
Validate before calling
if (outlet?.hasAttached()) {
portal.detach();
} Type guard
function isAttached(portal: Portal<any>, outlet: PortalOutlet | undefined): boolean {
return !!outlet && outlet.hasAttached();
} Try / catch
try {
portal.detach();
} catch (e) {
if (e instanceof Error && e.message.includes('not attached')) {
// already detached; nothing to do
} else {
throw e;
}
} Prevention
- Track attachment state in your component and only detach once
- Wrap cleanup code so teardown is idempotent
- Use outlet.hasAttached() before detaching
- Let CdkPortalOutlet handle cleanup on destroy instead of manual detach calls
When it happens
Trigger: Calling portal.detach() before portal.attach(outlet) was ever called; calling detach() twice; calling detach() after the host outlet has been destroyed and attachment state was lost.
Common situations: Cleanup code in ngOnDestroy that unconditionally detaches; re-executing a teardown function; a component destroyed before its portal attach logic ever ran; sharing a portal instance across hosts without tracking which host it is attached to.
Related errors
- Host already has a portal attached
- This PortalOutlet has already been disposed
- Attempting to attach dialog content after content is already
- Cannot attach component portal to outlet without an Applicat
- DOM portal content must be attached to a parent node.
AI-assisted analysis of angular/components@0411926e7d (2026-08-31).
Data as JSON: /api/errors/897aa473c1eb7467.
Report an issue: GitHub.