angular/angular-cli · error · PathIsFileException
Path "${p}" is a file.
Error message
Path "${p}" is a file. What it means
HostTree.getDir(path) returns the DirEntry for a path, but throws PathIsFileException when the path actually points to a file. Directory traversal APIs (dir(), subDirs, root) route through getDir, so the same throw occurs when one of those receives a file path.
Source
Thrown at packages/angular_devkit/schematics/src/tree/host-tree.ts:357
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) {
parent = null;
}
maybeCache = new HostDirEntry(parent && this.getDir(parent), p, this._recordSync, this);
this._dirCache.set(p, maybeCache);
}
return maybeCache;
}
visit(visitor: FileVisitor): void {
this.root.visit((path, entry) => {
visitor(path, entry);View on GitHub (pinned to bb72145f9a)
Solutions
- Verify the path is a directory before calling getDir: if (tree.exists(p)) it's a file — use tree.get(p) instead.
- Print/log the resolved path; fix the path construction so it targets a directory.
- If files named like directories are legal, branch on tree.exists() before choosing get vs getDir.
Example fix
// before
const dir = tree.getDir(targetPath);
// after
const dir = tree.exists(targetPath) ? undefined : tree.getDir(targetPath);
if (!dir) {
throw new Error(`${targetPath} is a file, expected a directory`);
} Defensive patterns
Strategy: validation
Validate before calling
if (tree.exists(dirPath)) {
throw new Error(`${dirPath} is a file, expected a directory`);
} Type guard
function isDirectory(tree: Tree, path: string): boolean {
return !tree.exists(path); // not a file; combined with getDir success means directory
} Try / catch
let dir;
try {
dir = tree.getDir(p);
} catch (e) {
if ((e as any).constructor?.name === 'PathIsFileException') {
// treat as file: tree.get(p)
} else throw e;
} Prevention
- Confirm directory paths from user config end where a folder actually exists
- Watch for files whose names collide with intended folder names (e.g. 'src' file)
- Branch on tree.exists() before choosing get vs getDir
- Use dirEntry.subDir with verified segment names
When it happens
Trigger: Calling tree.getDir(path), tree.dir(path), or dirEntry.subDir(...) where the path is an existing file; navigating with a segment that accidentally matches a file name (e.g. a file named 'src' or 'app').
Common situations: Building paths from user config where a value was intended to be a folder; projects that have files where directories were expected; off-by-one path joins that drop the final segment.
Related errors
- Path "${p}" is a directory.
- 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/ef6b8c68eb8891aa.
Report an issue: GitHub.