angular/angular-cli · error · InvalidSourceResultException

Invalid source result: ${_getTypeOfResult(value)}.

Error message

Invalid source result: ${_getTypeOfResult(value)}.

What it means

callSource validates the observable result of a Source: it must be a Tree (marked with the TreeSymbol). If a Source returns anything else (undefined, a rule, a plain object), InvalidSourceResultException is thrown with a type description. It catches Sources implemented incorrectly.

Source

Thrown at packages/angular_devkit/schematics/src/rules/call.ts:61

export class InvalidSourceResultException extends BaseException {
  constructor(value?: {}) {
    super(`Invalid source result: ${_getTypeOfResult(value)}.`);
  }
}

export function callSource(source: Source, context: SchematicContext): Observable<Tree> {
  return defer(async () => {
    let result: Tree | Observable<Tree> | undefined = source(context);

    if (isObservable(result)) {
      result = await lastValueFrom(result.pipe(defaultIfEmpty(undefined)));
    }

    if (result && TreeSymbol in result) {
      return result;
    }

    throw new InvalidSourceResultException(result);
  });
}

export function callRule(
  rule: Rule,
  input: Tree | Observable<Tree>,
  context: SchematicContext,
): Observable<Tree> {
  if (isObservable(input)) {
    return input.pipe(mergeMap((inputTree) => callRuleAsync(rule, inputTree, context)));
  } else {
    return defer(() => callRuleAsync(rule, input, context));
  }
}

async function callRuleAsync(rule: Rule, tree: Tree, context: SchematicContext): Promise<Tree> {
  let result = await rule(tree, context);

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Make the Source return a Tree: e.g. () => MergeStrategy-aware tree, or use callRule(rule, tree, context) inside a rule, not a source.
  2. If you meant to apply a rule, use callRule or chain in a Rule, not as a Source.
  3. Check that every code path in the custom source returns a Tree (no bare returns).

Example fix

// before
const mySource: Source = () => chain([rule1, rule2]); // returns a Rule
// after
const mySource: Source = (context) => callRule(chain([rule1, rule2]), empty(), context); // hmm: use empty() Tree
// or correct Source:
const mySource2: Source = () => empty();
Defensive patterns

Strategy: type-guard

Validate before calling

import { Tree } from '@angular-devkit/schematics';
function ensureTree(v: unknown): Tree {
  if (!v || !(TreeSymbol in (v as object))) throw new Error('Source must return a Tree');
  return v as Tree;
}

Type guard

function isTree(v: unknown): v is Tree {
  return !!v && typeof v === 'object' && TreeSymbol in (v as object);
}

Try / catch

try {
  const tree = await firstValueFrom(callSource(mySource, context));
} catch (err) {
  if (err instanceof InvalidSourceResultException) {
    console.error('Your Source must return a Tree, got:', err.message);
  }
}

Prevention

When it happens

Trigger: A custom Source callback that returns a non-Tree value — e.g. returning the result of callRule, a Rule function, undefined, or a promise/observable of a non-tree — consumed via callSource/apply/mergeWith.

Common situations: Writing a custom source that accidentally returns a Rule instead of a Tree; forgetting to return from the source callback (undefined); mixing up Source and Rule when composing pipelines.

Related errors


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