{"record":{"id":"7010475b1b801aff","repo":"angular/angular-cli","slug":"path-is-a-directory","errorCode":null,"errorMessage":"Path is a directory.","messagePattern":"Path is a directory\\.","errorType":"exception","errorClass":"PathIsDirectoryException","httpStatus":null,"severity":"error","filePath":"packages/angular_devkit/core/src/virtual-fs/host/memory.ts","lineNumber":159,"sourceCode":"          }\n        });\n      }\n    } while (parent != currentPath);\n  }\n\n  get capabilities(): HostCapabilities {\n    return { synchronous: true };\n  }\n\n  /**\n   * List of protected methods that give direct access outside the observables to the cache\n   * and internal states.\n   */\n  protected _write(path: Path, content: FileBuffer): void {\n    path = this._toAbsolute(path);\n    const old = this._cache.get(path);\n    if (old && old.isDirectory()) {\n      throw new PathIsDirectoryException(path);\n    }\n\n    // Update all directories. If we find a file we know it's an invalid write.\n    const fragments = split(path);\n    let curr: Path = normalize('/');\n    for (const fr of fragments) {\n      curr = join(curr, fr);\n      const maybeStats = this._cache.get(fr);\n      if (maybeStats) {\n        if (maybeStats.isFile()) {\n          throw new PathIsFileException(curr);\n        }\n      } else {\n        this._cache.set(curr, this._newDirStats());\n      }\n    }\n\n    // Create the stats.","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular_devkit/core/src/virtual-fs/host/memory.ts#L141-L177","documentation":"The Angular DevKit virtual file system (SimpleMemoryHost) maintains a cache of path -> stats entries. When you call write() on a path that is already recorded as a directory, _write detects the existing directory entry and throws PathIsDirectoryException. The memory host treats directories and files as mutually exclusive entries, so it refuses to overwrite a directory with file content instead of silently corrupting the tree.","triggerScenarios":"Calling host.write(dirPath, buffer) where dirPath was previously created with a directory record in the cache (e.g. via write of a path whose parent fragments created directory entries, or an explicit directory creation). In _write, `this._cache.get(path)` returns an entry whose `isDirectory()` is true, immediately throwing before any content is stored.","commonSituations":"Reusing a path that was intended to be a folder prefix (e.g. writing to 'src/assets' when it is an asset directory); path-building bugs that drop a filename segment so a directory path is passed to write(); schematic templates where a folder and file share a confusingly similar name; stale in-memory caches from earlier operations in the same process.","solutions":["Fix the caller so a file path (with filename segment) is passed to write() rather than the directory path.","Delete the directory entry first with host.delete(dirPath) before writing a file at that path, if overwriting is truly intended.","Check with host.isDirectory(path) (or read the stats) before writing, and branch to a different target path if it is a directory.","If the wrong entry was cached, rebuild the host or clear the offending entry and retry the operation."],"exampleFix":"// before\nhost.write(normalize('src/assets'), content);\n// after\nconst target = normalize('src/assets/logo.svg');\nif (host.isDirectory(target)) {\n  throw new Error('Refusing to write to a directory: ' + target);\n}\nhost.write(target, content);","handlingStrategy":"validation","validationCode":"import { normalize, Path } from '@angular-devkit/core';\n\nfunction assertWritableFile(host: { exists(p: Path): boolean; isDirectory(p: Path): boolean }, p: Path): void {\n  const abs = normalize(p);\n  if (host.exists(abs) && host.isDirectory(abs)) {\n    throw new Error(`Cannot write to '${abs}': it is a directory`);\n  }\n}","typeGuard":"function isFileEntry(entry: { isDirectory(): boolean; isFile(): boolean } | undefined): entry is { isDirectory(): boolean; isFile(): boolean; content: Buffer } {\n  return entry !== undefined && entry.isFile();\n}","tryCatchPattern":"import { PathIsDirectoryException } from '@angular-devkit/core';\n\ntry {\n  host.write(path, buffer);\n} catch (e) {\n  if (e instanceof PathIsDirectoryException) {\n    host.delete(e.path);\n    host.write(path, buffer);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always write to full file paths including the filename segment, never to directory prefixes.","Check isDirectory()/isFile() before every write to a path built from dynamic input.","Keep directory paths and file paths in separate typed variables to avoid mixing them."],"tags":["virtual-fs","file-system","angular-devkit","path"],"backgroundTag":"path-is-a-directory","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}