angular/components · error

Attempting to attach an unknown Portal type. BasePortalOutle

Error message

Attempting to attach an unknown Portal type. BasePortalOutlet accepts either a ComponentPortal or a TemplatePortal.

What it means

BasePortalOutlet.attach dispatches on portal type: ComponentPortal, TemplatePortal, or DomPortal. Anything else (or a malformed object) reaches the fallback `throwUnknownPortalTypeError`. It signals a wrong/incorrectly-typed argument rather than a runtime state issue.

Source

Thrown at src/cdk/portal/portal-errors.ts:38

 */
export function throwPortalAlreadyAttachedError() {
  throw Error('Host already has a portal attached');
}

/**
 * Throws an exception when attempting to attach a portal to an already-disposed host.
 * @docs-private
 */
export function throwPortalOutletAlreadyDisposedError() {
  throw Error('This PortalOutlet has already been disposed');
}

/**
 * Throws an exception when attempting to attach an unknown portal type.
 * @docs-private
 */
export function throwUnknownPortalTypeError() {
  throw Error(
    '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() {

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Pass a concrete `new ComponentPortal(MyComponent)` or `new TemplatePortal(templateRef, viewContainerRef)` instance
  2. Extend the correct Portal subclass for custom portals and keep the `_attachedHost`/type contract intact
  3. Remove incorrect casts (`as any`) hiding the type mismatch
  4. Update custom portal code when upgrading CDK versions to match the current Portal API

Example fix

// before
outlet.attach(this.portalDef as any); // plain object, throws
// after
import {ComponentPortal} from '@angular/cdk/portal';
outlet.attach(new ComponentPortal(this.portalDef.component));
Defensive patterns

Strategy: type-guard

Validate before calling

function isAttachablePortal(p: unknown): p is ComponentPortal<any> | TemplatePortal<any> | DomPortal {
  return p instanceof ComponentPortal || p instanceof TemplatePortal || p instanceof DomPortal;
}
if (isAttachablePortal(portal)) { outlet.attach(portal); }

Type guard

function isConcretePortal(v: unknown): v is ComponentPortal<any> | TemplatePortal<any> {
  return v instanceof ComponentPortal || v instanceof TemplatePortal;
}

Try / catch

try {
  outlet.attach(portal as any);
} catch (e) {
  if (e.message.includes('unknown Portal type')) {
    console.error('Expected ComponentPortal/TemplatePortal, got:', portal?.constructor?.name);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Passing a plain object cast as a Portal, a custom Portal subclass that does not override the type discriminator correctly, passing a `Portal` base instance instead of a concrete subclass, or an old/custom portal class from a different library version.

Common situations: DI misconfiguration returning the abstract Portal token; upgrading Angular/CDK where a custom portal no longer extends the expected class; wrapping portals in generics/proxies that erase the concrete type; typos such as passing the portal's component class instead of a ComponentPortal instance.

Related errors


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