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
- Check tree.exists(path) first — it returns true only for files — and handle directories with tree.getDir(path).
- Append the actual filename to the path before calling get.
- 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
- Always resolve module paths to concrete file names before tree.get
- Use tree.exists() (file-only) rather than raw get to distinguish
- Handle directories via DirEntry APIs (visit files, then get each)
- Log the normalized path when building paths dynamically
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
- Path "${p}" is a file.
- schematicName cannot be undefined.
- The "not" keyword is not supported in JSON Schema.
- Could not find (/.angular.json)
- Unknown schematics built-in module '${id}' requested from sc
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/9f17a94f3d10a31e.
Report an issue: GitHub.