angular/angular-cli · error · PathIsFileException
Path is a file.
Error message
Path is a file.
What it means
During _write, after handling the target itself, the memory host walks every fragment of the path from the root to ensure each intermediate segment is a directory. If any fragment lookup hits an existing FILE entry (`maybeStats.isFile()`), it throws PathIsFileException because a file cannot act as a parent directory. This keeps the in-memory tree structurally valid.
Source
Thrown at packages/angular_devkit/core/src/virtual-fs/host/memory.ts:170
* List of protected methods that give direct access outside the observables to the cache
* and internal states.
*/
protected _write(path: Path, content: FileBuffer): void {
path = this._toAbsolute(path);
const old = this._cache.get(path);
if (old && old.isDirectory()) {
throw new PathIsDirectoryException(path);
}
// Update all directories. If we find a file we know it's an invalid write.
const fragments = split(path);
let curr: Path = normalize('/');
for (const fr of fragments) {
curr = join(curr, fr);
const maybeStats = this._cache.get(fr);
if (maybeStats) {
if (maybeStats.isFile()) {
throw new PathIsFileException(curr);
}
} else {
this._cache.set(curr, this._newDirStats());
}
}
// Create the stats.
const stats: Stats<SimpleMemoryHostStats> = this._newFileStats(content, old);
this._cache.set(path, stats);
this._updateWatchers(path, old ? HostWatchEventType.Changed : HostWatchEventType.Created);
}
protected _read(path: Path): FileBuffer {
path = this._toAbsolute(path);
const maybeStats = this._cache.get(path);
if (!maybeStats) {
throw new FileDoesNotExistException(path);
} else if (maybeStats.isDirectory()) {
throw new PathIsDirectoryException(path);View on GitHub (pinned to bb72145f9a)
Solutions
- Fix the constructed path so no intermediate segment is an existing file; inspect each fragment with host.exists()/host.isFile().
- Rename or delete the conflicting file entry if it is no longer needed, then retry the write.
- Use a different output location to avoid a file name doubling as a directory name.
- Normalize/validate user-supplied or config-supplied paths before passing them to write().
Example fix
// before host.write(join(basePath, 'README.md', 'intro.txt'), content); // README.md is a file // after const target = join(basePath, 'docs', 'intro.txt'); host.write(target, content);
Defensive patterns
Strategy: validation
Validate before calling
import { join, normalize, Path, split } from '@angular-devkit/core';
function assertValidFilePath(host: { exists(p: Path): boolean; isFile(p: Path): boolean }, filePath: Path): void {
let curr: Path = normalize('/');
for (const fr of split(normalize(filePath))) {
curr = join(curr, fr);
if (host.exists(curr) && host.isFile(curr) && curr !== normalize(filePath)) {
throw new Error(`'${curr}' is a file but is used as a directory in path '${filePath}'`);
}
}
} Try / catch
import { PathIsFileException } from '@angular-devkit/core';
try {
host.write(path, buffer);
} catch (e) {
if (e instanceof PathIsFileException) {
throw new Error(`Fix path construction: '${e.path}' collides with an existing file`);
}
throw e;
} Prevention
- Validate user/config-provided base paths to ensure they are directories, not files.
- Join paths with the library's join() instead of string concatenation to avoid missing separators.
- Before creating deep paths, verify no intermediate segment name is already registered as a file.
When it happens
Trigger: Calling host.write('some/existingfile.txt/child.txt', content) — the fragment 'existingfile.txt' exists in the cache as a file, so creating 'child.txt' under it throws. Also triggered when a prior write created a file whose name now collides with a directory component of a deeper path.
Common situations: Joining paths from user input or config where a filename accidentally becomes a folder (e.g. baseDir already contains a filename); path concat bugs with template strings ('path' + file) missing a separator; case where a schematic generated 'foo' as a file earlier and later writes 'foo/bar'.
Related errors
- Path is a directory.
- File does not exist.
- File already exist.
- File already exist.
- Path ${JSON.stringify(path)} must be absolute.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/bbda38e7b62d40f1.
Report an issue: GitHub.