angular/angular · error · FatalLinkerError
Unsupported `forwardRef(fn)` call, expected its argument to
Error message
Unsupported `forwardRef(fn)` call, expected its argument to be a function
What it means
Thrown by extractForwardRef() in the Angular partial-declaration linker when a forwardRef(...) call's single argument is not a function. The linker unwraps the forward reference by reading the wrapper function's return value (getFunctionReturnValue()); passing anything else (a string, class reference directly, object literal) makes unwrapping impossible and FatalLinkerError is thrown.
Source
Thrown at packages/compiler-cli/linker/src/file_linker/partial_linkers/util.ts:106
const callee = expr.getCallee();
if (callee.getSymbolName() !== 'forwardRef') {
throw new FatalLinkerError(
callee.expression,
'Unsupported expression, expected a `forwardRef()` call or a type reference',
);
}
const args = expr.getArguments();
if (args.length !== 1) {
throw new FatalLinkerError(
expr,
'Unsupported `forwardRef(fn)` call, expected a single argument',
);
}
const wrapperFn = args[0] as AstValue<Function, TExpression>;
if (!wrapperFn.isFunction()) {
throw new FatalLinkerError(
wrapperFn,
'Unsupported `forwardRef(fn)` call, expected its argument to be a function',
);
}
return createMayBeForwardRefExpression(
wrapperFn.getFunctionReturnValue().getOpaque(),
ForwardRefHandling.Unwrapped,
);
}
const STANDALONE_IS_DEFAULT_RANGE = new semver.Range(`>= 19.0.0 || ${PLACEHOLDER_VERSION}`, {
includePrerelease: true,
});
export function getDefaultStandaloneValue(version: string): boolean {
return STANDALONE_IS_DEFAULT_RANGE.test(version);
}View on GitHub (pinned to 51cb07e980)
Solutions
- Always pass a function: forwardRef(() => AppModule)
- If you do not need the forward reference, drop the wrapper entirely and use a plain type reference (providedIn: AppModule)
- Fix the generator that emits the non-function argument
- Restore the library's original published output instead of an edited copy
Example fix
// before providedIn: forwardRef(AppModule) // after providedIn: forwardRef(() => AppModule)
Defensive patterns
Strategy: type-guard
Validate before calling
// Validate that forwardRef's argument is a function before emitting metadata
if (node.arguments[0]?.type !== 'ArrowFunctionExpression' && node.arguments[0]?.type !== 'FunctionExpression') {
throw new Error('forwardRef argument must be a function, e.g. forwardRef(() => Token)');
} Type guard
function isForwardRefFnArg(node: any): node is {type: 'ArrowFunctionExpression' | 'FunctionExpression'} {
return node?.type === 'ArrowFunctionExpression' || node?.type === 'FunctionExpression';
} Try / catch
try {
fileLinker.linkPartialDeclaration(fnName, args, scope);
} catch (e) {
if (e instanceof FatalLinkerError && /argument to be a function/.test(e.message)) {
throw new Error(`${sourceUrl}: forwardRef must wrap a function returning the token.`);
}
throw e;
} Prevention
- Write forwardRef(() => Token), never forwardRef(Token) or forwardRef('Token')
- Skip the wrapper entirely when the reference is not circular: providedIn: Token
- Let the Angular compiler generate these expressions instead of hand-writing them
When it happens
Trigger: `providedIn: forwardRef('AppModule')` or `providedIn: forwardRef(AppModule)` inside ɵɵngDeclare* metadata — forwardRef requires a lambda that returns the token, not the token itself. Typically hand-written declarations or codegen that 'simplifies' the wrapper away.
Common situations: Hand-authored partial declarations and linker test fixtures; code generators emitting the class reference instead of an arrow function; refactoring tools inlining what looks like a redundant wrapper.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- Unsupported `forwardRef(fn)` call, expected a single argumen
- Unsupported type, its name could not be determined
- Unsupported expression, expected a `forwardRef()` call or a
- Unsupported encapsulation
- Expected change detection strategy to have a symbol name
AI-assisted analysis of angular/angular@51cb07e980 (2026-08-22).
Data as JSON: /api/errors/01d94a7c90184926.
Report an issue: GitHub.