angular/angular-cli · error · Error
tried to insert ${toInsert} as first occurence with no fallb
Error message
tried to insert ${toInsert} as first occurence with no fallback position What it means
insertAfterLastOccurrence (a shared AST mutation helper in ast-utils) computes the insertion position from the last occurrence of the given syntax kind among the found nodes. If no nodes were found and no explicit fallbackPos was provided, it cannot determine where to insert and throws this Error.
Source
Thrown at packages/schematics/angular/utility/ast-utils.ts:253
*/
export function insertAfterLastOccurrence(
nodes: ts.Node[] | ts.NodeArray<ts.Node>,
toInsert: string,
file: string,
fallbackPos: number,
syntaxKind?: ts.SyntaxKind,
): Change {
let lastItem: ts.Node | undefined;
for (const node of nodes) {
if (!lastItem || lastItem.getStart() < node.getStart()) {
lastItem = node;
}
}
if (syntaxKind && lastItem) {
lastItem = findNodes(lastItem, syntaxKind).sort(nodesByPosition).pop();
}
if (!lastItem && fallbackPos == undefined) {
throw new Error(`tried to insert ${toInsert} as first occurence with no fallback position`);
}
const lastItemPosition: number = lastItem ? lastItem.getEnd() : fallbackPos;
return new InsertChange(file, lastItemPosition, toInsert);
}
function _angularImportsFromNode(node: ts.ImportDeclaration): { [name: string]: string } {
const ms = node.moduleSpecifier;
let modulePath: string;
switch (ms.kind) {
case ts.SyntaxKind.StringLiteral:
modulePath = (ms as ts.StringLiteral).text;
break;
default:
return {};
}
if (!modulePath.startsWith('@angular/')) {View on GitHub (pinned to bb72145f9a)
Solutions
- Pass an explicit `fallbackPos` (e.g. 0 or end-of-file offset) when calling insertAfterLastOccurrence on files that may lack the expected node.
- Verify the target file contains the expected syntax (e.g. existing imports) before mutating; create/normalize the file first.
- Use ts.createSourceFile to inspect the file and adjust the syntaxKind argument to one actually present.
- Regenerate or fix the malformed source file that the codemod is targeting.
Example fix
// before const change = insertAfterLastOccurrence(nodes, toInsert, file, undefined, ts.SyntaxKind.CommaToken); // after const change = insertAfterLastOccurrence(nodes, toInsert, file, 0, ts.SyntaxKind.CommaToken);
Defensive patterns
Strategy: try-catch
Validate before calling
const imports = source.statements.filter(ts.isImportDeclaration);
if (imports.length === 0) {
console.warn('No import declarations found; pass an explicit fallbackPos to insertAfterLastOccurrence.');
} Type guard
function hasNodes(nodes: ts.Node[]): nodes is [ts.Node, ...ts.Node[]] {
return nodes.length > 0;
} Try / catch
try {
const change = insertAfterLastOccurrence(nodes, toInsert, file, fallbackPos ?? 0, syntaxKind);
} catch (e) {
if (String(e?.message).includes('no fallback position')) {
// file lacks the expected node; insert at a known position instead
}
} Prevention
- Always provide a fallbackPos when writing custom codemods with ast-utils.
- Inspect the target file's AST before mutating; guard for empty or comment-only files.
- Pin ast-utils usage to the Angular version matching the files being transformed.
- Test codemods against empty and minimal file fixtures.
When it happens
Trigger: Calling helpers like insertImport or addRouteDeclarationToModule against a source file whose AST contains no node of the expected syntax kind (e.g. importing into an empty/nonexistent imports section) without passing a fallbackPos, or passing an incorrect syntaxKind for the file's content shape.
Common situations: Custom schematics built on ast-utils running against files that don't match the expected structure (empty files, files with only comments, non-TS content); upgrading Angular where file templates changed; passing wrong syntax kind when writing custom codemods.
Related errors
- Cannot find the "provideServerRendering" function call in "$
- Couldn't find a route declaration in ${fileToAdd}.\nUse the
- The router module method doesn't have arguments at line ${li
- No route declaration array was found that corresponds to rou
- Class name "${className}" is invalid.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/fa4bff5ca9d99f99.
Report an issue: GitHub.