angular/components · error · SchematicsException

Could not read file for path: ${htmlFilePath}

Error message

Could not read file for path: ${htmlFilePath}

What it means

appendHtmlElementToHead in src/cdk/schematics/utils/html-manipulation.ts reads the target HTML file (normally the app's index.html) from the schematic virtual host Tree before appending an element to its <head>. If host.read(htmlFilePath) returns null the file does not exist at that path in the virtual file system, and a SchematicsException is thrown. The library cannot modify a file it cannot read, so it fails fast.

Source

Thrown at src/cdk/schematics/utils/html-manipulation.ts:18

/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */

import {SchematicsException, Tree} from '@angular-devkit/schematics';
import {Element, getChildElementIndentation} from './parse5-element';
import {parse as parseHtml} from 'parse5';

/** Appends the given element HTML fragment to the `<head>` element of the specified HTML file. */
export function appendHtmlElementToHead(host: Tree, htmlFilePath: string, elementHtml: string) {
  const htmlFileBuffer = host.read(htmlFilePath);

  if (!htmlFileBuffer) {
    throw new SchematicsException(`Could not read file for path: ${htmlFilePath}`);
  }

  const htmlContent = htmlFileBuffer.toString();

  if (htmlContent.includes(elementHtml)) {
    return;
  }

  const headTag = getHtmlHeadTagElement(htmlContent);

  if (!headTag) {
    throw Error(`Could not find '<head>' element in HTML file: ${htmlFileBuffer}`);
  }

  // We always have access to the source code location here because the `getHeadTagElement`
  // function explicitly has the `sourceCodeLocationInfo` option enabled.
  const endTagOffset = headTag.sourceCodeLocation!.endTag!.startOffset;
  const indentationOffset = getChildElementIndentation(headTag);

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Verify the project's build architect options in angular.json contain a correct "index" path and that the file exists on disk.
  2. Restore or recreate index.html at the configured path (a standard Angular app has src/index.html).
  3. If you use a custom index name, register it under projects.<name>.architect.build.options.index so schematics can resolve it.
  4. Re-run `ng build` or `ng serve` once to confirm the workspace resolves the index file, then retry the schematic.

Example fix

// before (angular.json)
"options": { "main": "src/main.ts" }
// after (angular.json)
"options": { "main": "src/main.ts", "index": "src/index.html" }
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'fs';
const index = JSON.parse(fs.readFileSync('angular.json', 'utf8'))
  .projects[name]?.architect?.build?.options?.index ?? 'src/index.html';
if (!existsSync(index)) throw new Error(`index.html missing at ${index}`);

Type guard

function hasIndexOption(opts: Record<string, unknown> | undefined): opts is Record<string, unknown> & { index: string } {
  return !!opts && typeof opts.index === 'string';
}

Try / catch

try {
  await runSchematic('add-fonts', { project: name });
} catch (e) {
  if (String(e.message).startsWith('Could not read file for path')) {
    console.error('index.html not found; verify the project build "index" option.');
  } else throw e;
}

Prevention

When it happens

Trigger: Running a schematic that injects into index.html (e.g. addFontsToIndex for Material typography/fonts) when the resolved index path does not exist in the Tree; a project whose architect build options lack an index entry the schematic can resolve; an unusual custom index file name/location not registered in angular.json.

Common situations: Custom index filename (e.g. src/index.dev.html) not declared in angular.json; index.html deleted or moved during refactoring; monorepo layouts where sourceRoot does not point at the app root; running the schematic on a partially generated project.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/7c72ea9b36ec5b64. Report an issue: GitHub.