angular/angular-cli · error · SchematicEngineConflictingException

A schematic was called from a different engine as its parent

Error message

A schematic was called from a different engine as its parent.

What it means

Each SchematicEngine instance owns its own collection/schematic registries and task schedulers. When creating an execution context for a schematic, if the supplied parent context carries an "engine" reference that is a different engine instance than the one being asked to create the context, the parent-child relationship is invalid, so SchematicEngineConflictingException is thrown. The engine refuses to mix contexts across engine instances because task scheduling and merge strategies would otherwise be attributed to the wrong engine.

Source

Thrown at packages/angular_devkit/schematics/src/engine/engine.ts:248

          description,
          new Set(parentNames),
        );

        bases.unshift(base, ...baseBases);
      }
    }

    return [description, bases];
  }

  createContext(
    schematic: Schematic<CollectionT, SchematicT>,
    parent?: Partial<TypedSchematicContext<CollectionT, SchematicT>>,
    executionOptions?: Partial<ExecutionOptions>,
  ): TypedSchematicContext<CollectionT, SchematicT> {
    // Check for inconsistencies.
    if (parent && parent.engine && parent.engine !== this) {
      throw new SchematicEngineConflictingException();
    }

    let interactive = true;
    if (executionOptions && executionOptions.interactive != undefined) {
      interactive = executionOptions.interactive;
    } else if (parent && parent.interactive != undefined) {
      interactive = parent.interactive;
    }

    let context: TypedSchematicContext<CollectionT, SchematicT> = {
      debug: (parent && parent.debug) || false,
      engine: this,
      logger:
        (parent && parent.logger && parent.logger.createChild(schematic.description.name)) ||
        new logging.NullLogger(),
      schematic,
      strategy:
        parent && parent.strategy !== undefined ? parent.strategy : this.defaultMergeStrategy,

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Invoke createContext on the same engine instance that owns the parent context (use parent.engine.createContext(...) instead of a different engine).
  2. Ensure a single SchematicEngine instance is created per execution and pass that one to all schematic/code invocations.
  3. If crossing engines is intentional, omit the "engine" field on the parent (pass a parent without engine) or don't pass a parent at all.
  4. In nested schematic calls, use the current context's engine (context.engine) rather than constructing a new engine.

Example fix

// before
const otherEngine = new SchematicEngine(host);
const ctx = otherEngine.createContext(schematic, parentContext); // parentContext.engine !== otherEngine

// after
const ctx = parentContext.engine.createContext(schematic, parentContext);
Defensive patterns

Strategy: validation

Validate before calling

function canUseAsParent(engine: SchematicEngine, parent?: Partial<TypedSchematicContext<any, any>>): boolean {
  return !parent || !parent.engine || parent.engine === engine;
}
if (canUseAsParent(engine, parentContext)) {
  engine.createContext(schematic, parentContext);
}

Type guard

function belongsToEngine<T, C extends { engine?: unknown }>(engine: SchematicEngine<T, any>, ctx: C): ctx is C & { engine: SchematicEngine<T, any> } {
  return ctx.engine === undefined || ctx.engine === engine;
}

Try / catch

import { SchematicEngineConflictingException } from '@angular-devkit/schematics';
try {
  const ctx = engine.createContext(schematic, parentContext);
} catch (e) {
  if (e instanceof SchematicEngineConflictingException) {
    const ctx = parentContext.engine.createContext(schematic, parentContext);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling engine.createContext(schematic, parentContext) where parentContext.engine is set and !== the engine instance the method is invoked on — typically when schematic code captures a context from one engine (e.g. created by an external SchematicEngine) and passes it as parent to another engine's createContext, or when invoking a schematic through a second engine instance while passing the first engine's context along.

Common situations: Custom CLI or builder code that instantiates more than one SchematicEngine and shares contexts between them; library code that stores a global parent context and reuses it after a new engine was created (common in tests that build a fresh engine per test); running a schematic inside another schematic but through a separately constructed engine instead of engine.registry/context from the current context.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/1a94f87f82e5f2a4. Report an issue: GitHub.