angular/angular-cli · error · PathIsDirectoryException

Path "${p}" is a directory.

Error message

Path "${p}" is a directory.

What it means

HostTree.get(path) returns the FileEntry for a file, or null if it doesn't exist — but if the path points to a directory it throws PathIsDirectoryException with this message. The API distinguishes 'missing' (null) from 'wrong type' (throw), because a directory has no file content to return.

Source

Thrown at packages/angular_devkit/schematics/src/tree/host-tree.ts:345

    // If there is a parse error throw with the error information
    if (errors[0]) {
      const { error, offset } = errors[0];
      throw new Error(
        `Failed to parse "${path}" as JSON. ${printParseErrorCode(error)} at offset: ${offset}.`,
      );
    }

    return result;
  }

  exists(path: string): boolean {
    return this._recordSync.isFile(this._normalizePath(path));
  }

  get(path: string): FileEntry | null {
    const p = this._normalizePath(path);
    if (this._recordSync.isDirectory(p)) {
      throw new PathIsDirectoryException(p);
    }
    if (!this._recordSync.exists(p)) {
      return null;
    }

    return new LazyFileEntry(p, () => Buffer.from(this._recordSync.read(p)));
  }

  getDir(path: string): DirEntry {
    const p = this._normalizePath(path);
    if (this._recordSync.isFile(p)) {
      throw new PathIsFileException(p);
    }

    let maybeCache = this._dirCache.get(p);
    if (!maybeCache) {
      let parent: Path | null = dirname(p);
      if (p === parent) {

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Check tree.exists(path) first — it returns true only for files — and handle directories with tree.getDir(path).
  2. Append the actual filename to the path before calling get.
  3. If the path may be either, branch: if tree.getDir(path) doesn't throw, treat it as a directory.

Example fix

// before
const entry = tree.get(dirPath);
// after
if (tree.exists(dirPath)) {
  const entry = tree.get(dirPath);
} else if (tree.getDir(dirPath)) {
  // it's a directory: use DirEntry APIs instead
}
Defensive patterns

Strategy: validation

Validate before calling

if (tree.exists(p)) { /* it's a file: safe to tree.get(p) */ }
else if (!tree.getDir.exists) { /* neither */ }

Type guard

function isFileEntry(tree: Tree, path: string): boolean {
  return tree.exists(path); // exists() is file-only in HostTree
}

Try / catch

let entry;
try {
  entry = tree.get(p);
} catch (e) {
  if ((e as any).constructor?.name === 'PathIsDirectoryException') {
    const dir = tree.getDir(p); // handle directory case
  } else throw e;
}

Prevention

When it happens

Trigger: Calling tree.get(path) or tree.read(path) with a path that resolves to a directory in the virtual tree, e.g. a directory-style import path ('/src/assets' with no file extension) or passing tree.root.path.

Common situations: Resolving module specifiers that omit the filename; glob/visitor logic that forwards directory paths into get; misconfigured template paths pointing at folders.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/9f17a94f3d10a31e. Report an issue: GitHub.