angular/angular-cli · error · FileAlreadyExistException

Path "${path}" already exist.

Error message

Path "${path}" already exist.

What it means

FileAlreadyExistException is thrown by the Sink abstraction (via _fileAlreadyExistException) when validating a CreateFileAction whose target path already exists in the sink. Schematics treats 'create' as strictly creating a new file; overwriting is a separate 'overwrite' action. This keeps tree operations explicit and prevents accidental clobbering of existing files.

Source

Thrown at packages/angular_devkit/schematics/src/sink/sink.ts:56

export abstract class SimpleSinkBase implements Sink {
  preCommitAction: (action: Action) => void | Action | PromiseLike<Action> | Observable<Action> =
    Noop;
  postCommitAction: (action: Action) => void | Observable<void> = Noop;
  preCommit: () => void | Observable<void> = Noop;
  postCommit: () => void | Observable<void> = Noop;

  protected abstract _validateFileExists(p: string): Observable<boolean>;

  protected abstract _overwriteFile(path: string, content: Buffer): Observable<void>;
  protected abstract _createFile(path: string, content: Buffer): Observable<void>;
  protected abstract _renameFile(path: string, to: string): Observable<void>;
  protected abstract _deleteFile(path: string): Observable<void>;

  protected abstract _done(): Observable<void>;

  protected _fileAlreadyExistException(path: string): void {
    throw new FileAlreadyExistException(path);
  }
  protected _fileDoesNotExistException(path: string): void {
    throw new FileDoesNotExistException(path);
  }

  protected _validateOverwriteAction(action: OverwriteFileAction): Observable<void> {
    return this._validateFileExists(action.path).pipe(
      map((b) => {
        if (!b) {
          this._fileDoesNotExistException(action.path);
        }
      }),
    );
  }
  protected _validateCreateAction(action: CreateFileAction): Observable<void> {
    return this._validateFileExists(action.path).pipe(
      map((b) => {
        if (b) {

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Check existence first: if (tree.exists(path)) use tree.overwrite(path, content) instead of tree.create(path, content).
  2. Delete the stale file before committing, or skip creation when the content is identical.
  3. Wrap commit in try/catch for FileAlreadyExistException to handle idempotent re-runs explicitly.

Example fix

// before
tree.create('src/app.config.ts', content);
// after
if (tree.exists('src/app.config.ts')) {
  tree.overwrite('src/app.config.ts', content);
} else {
  tree.create('src/app.config.ts', content);
}
Defensive patterns

Strategy: validation

Validate before calling

if (tree.exists('/src/app.config.ts')) { /* use overwrite instead of create */ }

Type guard

null

Try / catch

try { host.commit(tree); } catch (e) { if (e instanceof FileAlreadyExistException) { /* skip or overwrite */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling host.commitSingleAction() or commit() with a 'c' (create) action for a path that already exists in the underlying host, e.g. a schematic used rule/branch().create() or Tree.create() on an existing file path.

Common situations: Running a schematic twice where it unconditionally creates a file; generator templates that use `host.create('src/config.ts', ...)` without checking `host.exists()`; merging trees where both sides create the same new file.

Related errors


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