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

  1. Check attachment state first: only call detach() if the portal is attached (e.g. wrap in try/catch or track attached outlet yourself)
  2. Guard cleanup with an attached flag: if (this.attached) { portal.detach(); this.attached = false; }
  3. Use the outlet's detach() (DomPortalOutlet.detach / CdkPortalOutlet.detach) only after verifying it has an attached portal (outlet.hasAttached())
  4. 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

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


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/897aa473c1eb7467. Report an issue: GitHub.