angular/angular-cli · error · InvalidRuleResultException
Invalid rule result: ${_getTypeOfResult(value)}.
Error message
Invalid rule result: ${_getTypeOfResult(value)}. What it means
callRule (async path) requires every Rule to return a Tree, an Observable<Tree>, or void/undefined for in-place mutation. When the rule's resolved result is a truthy value that is not a Tree (no TreeSymbol), InvalidRuleResultException is thrown. It enforces the Rule return contract.
Source
Thrown at packages/angular_devkit/schematics/src/rules/call.ts:97
while (typeof result === 'function') {
// This is considered a Rule, chain the rule and return its output.
result = await result(tree, context);
}
if (typeof result === 'undefined') {
return tree;
}
if (isObservable(result)) {
result = await lastValueFrom(result.pipe(defaultIfEmpty(tree)));
}
if (result && TreeSymbol in result) {
return result;
}
throw new InvalidRuleResultException(result);
}
View on GitHub (pinned to bb72145f9a)
Solutions
- Return the input tree from the rule (or nothing) so the contract Tree|Observable<Tree>|void is met.
- If you need async work, return an Observable<Tree> (e.g. from(callRule(...))) not a Promise of another value.
- Remove accidental returns: wrap the value-producing call in a statement without returning it.
Example fix
// before
return (tree: Tree) => tree.visit(f => log(f.path)); // visit returns void-ish, not a Tree
// after
return (tree: Tree) => { tree.visit(f => log(f.path)); return tree; }; Defensive patterns
Strategy: type-guard
Validate before calling
function ensureRuleResult(v: unknown): Tree | Observable<Tree> | void {
if (v === undefined) return v;
if (v && typeof v === 'object' && TreeSymbol in (v as object)) return v as Tree;
throw new Error('Rule must return Tree | Observable<Tree> | void');
} Type guard
function isRuleResult(v: unknown): v is Tree | Observable<Tree> | undefined {
return v === undefined || (typeof v === 'object' && v !== null && (TreeSymbol in (v as object) || typeof (v as any).subscribe === 'function'));
} Try / catch
try {
await firstValueFrom(callRule(myRule, tree, context));
} catch (err) {
if (err instanceof InvalidRuleResultException) {
console.error('Rule returned a non-Tree value:', err.message);
}
} Prevention
- Annotate rules with the Rule type so wrong returns fail at compile time.
- Avoid `return tree.visit(...)` and other accidental non-Tree returns.
- For async work return Observable<Tree>, not Promise<other>.
When it happens
Trigger: A Rule returning something other than Tree|Observable<Tree>|void — e.g. returning a string, a FileEntry, a Promise of a non-tree, or an object literal.
Common situations: Custom rules that accidentally `return tree.visit(...)` (returns void/false-y data), `return someOtherCall()` leaking a non-tree, or TypeScript types bypassed with `as any`.
Related errors
- Invalid source result: ${_getTypeOfResult(value)}.
- schematicName cannot be undefined.
- The "not" keyword is not supported in JSON Schema.
- Could not find (/.angular.json)
- Unknown schematics built-in module '${id}' requested from sc
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/b5b343d09f225b96.
Report an issue: GitHub.