angular/angular · error · FatalDiagnosticError
LOCAL_COMPILATION_UNSUPPORTED_EXPRESSION
LOCAL_COMPILATION_UNSUPPORTED_EXPRESSION
Error message
In ${compilationModeName} mode, host directive cannot be an expression. Use an identifier instead What it means
In local compilation mode (tsconfig `angularCompilerOptions.compilationMode: "local"`, or experimental declaration-only emission) each file is compiled without full-program context, so hostDirectives entries must be plain identifiers or property-access chains resolvable locally. An entry that is an arbitrary expression — typically `forwardRef(() => Dir)` — cannot be processed and is rejected with LOCAL_COMPILATION_UNSUPPORTED_EXPRESSION at that expression node.
Source
Thrown at packages/compiler-cli/src/ngtsc/annotations/directive/src/shared.ts:2154
}
}
let directive: Reference<ClassDeclaration> | Expression | ExternalReference;
let nameForErrors = (fieldName: string) => '@Directive.hostDirectives';
if (compilationMode === CompilationMode.LOCAL && hostReference instanceof DynamicValue) {
// At the moment in local compilation we only support simple array for host directives, i.e.,
// an array consisting of the directive identifiers. We don't support forward refs or other
// expressions applied on externally imported directives. The main reason is simplicity, and
// that almost nobody wants to use host directives this way (e.g., what would be the point of
// forward ref for imported symbols?!)
if (
!ts.isIdentifier(hostReference.node) &&
!ts.isPropertyAccessExpression(hostReference.node)
) {
const compilationModeName = emitDeclarationOnly
? 'experimental declaration-only emission'
: 'local compilation';
throw new FatalDiagnosticError(
ErrorCode.LOCAL_COMPILATION_UNSUPPORTED_EXPRESSION,
hostReference.node,
`In ${compilationModeName} mode, host directive cannot be an expression. Use an identifier instead`,
);
}
directive = new WrappedNodeExpr(hostReference.node);
} else if (hostReference instanceof Reference) {
directive = hostReference as Reference<ClassDeclaration>;
nameForErrors = (fieldName: string) =>
`@Directive.hostDirectives.${
(directive as Reference<ClassDeclaration>).node.name.text
}.${fieldName}`;
} else {
throw new Error('Impossible state');
}
const meta: HostDirectiveMeta = {
directive,View on GitHub (pinned to 51cb07e980)
Solutions
- Import the directive class and reference it directly: `hostDirectives: [MenuHost]`
- Break the circular import that motivated forwardRef (restructure files, or use `import type` for type-only usage)
- Fall back to full compilation mode if the expression form is genuinely required
Example fix
// before
@Directive({selector: 'menu', hostDirectives: [forwardRef(() => MenuHost)]})
class Menu {}
// after
import {MenuHost} from './menu-host';
@Directive({selector: 'menu', hostDirectives: [MenuHost]})
class Menu {} Defensive patterns
Strategy: validation
Validate before calling
const HOSTDIR_EXPR = /hostDirectives\s*:\s*\[[^\]]*(forwardRef|\bfunction\b|\(\s*\(\s*\))/; // CI gate: fail when compilationMode is local (or emitDeclarationOnly) and the // hostDirectives array contains anything but identifiers/property accesses: // rg -n "hostDirectives.*forwardRef" src/ // rg -n '"compilationMode"\s*:\s*"local"' tsconfig*
Prevention
- In local/declaration-only compilation, hostDirectives entries must be plain (property-access) identifiers — import the class and reference it directly
- Eliminate forwardRef in hostDirectives by fixing the circular import (split files, or use import type for type-only references)
- Grep for forwardRef inside hostDirectives whenever enabling compilationMode local
When it happens
Trigger: `@Directive({hostDirectives: [forwardRef(() => MenuHost)]})` compiled with compilationMode 'local' or emitDeclarationOnly; also IIFE/call expressions or conditional expressions inside the hostDirectives array.
Common situations: Libraries opting into local/partial compilation for faster builds; forwardRef copied from View-Engine-era code to break circular imports; declaration-only builds (ngtsc emitDeclarationOnly) hitting the same restriction.
Related errors
- DECORATOR_UNEXPECTED
- DECORATOR_ARITY_WRONG
- DECORATOR_ARG_NOT_LITERAL
- DUPLICATE_DECORATED_PROPERTIES
- IMPORT_CYCLE_DETECTED
AI-assisted analysis of angular/angular@51cb07e980 (2026-08-22).
Data as JSON: /api/errors/3e64ca5115d7ff23.
Report an issue: GitHub.