{"record":{"id":"cdb5bae664bad1a0","repo":"angular/angular-cli","slug":"content-at-path-path-has-changed-between-the","errorCode":null,"errorMessage":"Content at path \"${path}\" has changed between the start and the end of an update.","messagePattern":"Content at path \"(.+?)\" has changed between the start and the end of an update\\.","errorType":"exception","errorClass":"ContentHasMutatedException","httpStatus":null,"severity":"error","filePath":"packages/angular_devkit/schematics/src/tree/host-tree.ts","lineNumber":401,"sourceCode":"      throw new FileDoesNotExistException(p);\n    }\n    const c = typeof content == 'string' ? Buffer.from(content) : content;\n    this._record.overwrite(p, c as {} as virtualFs.FileBuffer).subscribe();\n  }\n  beginUpdate(path: string): UpdateRecorder {\n    const entry = this.get(path);\n    if (!entry) {\n      throw new FileDoesNotExistException(path);\n    }\n\n    return UpdateRecorderBase.createFromFileEntry(entry);\n  }\n  commitUpdate(record: UpdateRecorder): void {\n    if (record instanceof UpdateRecorderBase) {\n      const path = record.path;\n      const entry = this.get(path);\n      if (!entry) {\n        throw new ContentHasMutatedException(path);\n      } else {\n        const newContent = record.apply(entry.content);\n        if (!newContent.equals(entry.content)) {\n          this.overwrite(path, newContent);\n        }\n      }\n    } else {\n      throw new InvalidUpdateRecordException();\n    }\n  }\n\n  // Structural methods.\n  create(path: string, content: Buffer | string): void {\n    const c = typeof content == 'string' ? Buffer.from(content) : content;\n    this._record.create(this._normalizePath(path), c as {} as virtualFs.FileBuffer).subscribe();\n  }\n  delete(path: string): void {\n    this._recordSync.delete(this._normalizePath(path));","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular_devkit/schematics/src/tree/host-tree.ts#L383-L419","documentation":"Thrown by HostTree.commitUpdate when the file targeted by the UpdateRecorder can no longer be found in the tree — the content/path mutated between beginUpdate and commitUpdate. This guards against applying text edits computed against stale content, which would silently corrupt the file.","triggerScenarios":"Deleting, renaming, or re-creating the file (or overwriting it and having commitUpdate re-read different content) between tree.beginUpdate(path) and tree.commitUpdate(record); running nested rules that mutate the same file inside an update session; using a recorder whose entry was captured before a merge/branch operation.","commonSituations":"Schematics that delete-and-recreate a file while an update recorder is open; concurrent rules mutating the same file; a rule that commits other changes mid-update.","solutions":["Complete the update (commitUpdate) before any other tree mutation of the same path.","Don't delete/rename/recreate the file while holding an open UpdateRecorder.","Recreate the recorder after intermediate mutations: beginUpdate again after changes, then edit and commit.","If using applyChanges-style flows, ensure each commitUpdate immediately follows its beginUpdate."],"exampleFix":"// before\nconst rec = tree.beginUpdate(p);\ntree.delete(p);\ntree.create(p, other);\ntree.commitUpdate(rec);\n// after\nconst rec = tree.beginUpdate(p);\n// ...edits only...\ntree.commitUpdate(rec);\ntree.delete(p);\ntree.create(p, mergedContent);","handlingStrategy":"try-catch","validationCode":"const before = tree.get(path)?.content;\n// ...after edits, before commit:\nconst unchanged = tree.get(path)?.content?.equals(before!);","typeGuard":null,"tryCatchPattern":"try {\n  tree.commitUpdate(record);\n} catch (e) {\n  if ((e as Error).message.includes('Content has mutated')) {\n    // restart: re-beginUpdate on current content and reapply edits\n  } else throw e;\n}","preventionTips":["Never delete/rename/recreate a file between beginUpdate and commitUpdate","Commit the recorder immediately after edits, before other tree mutations","Avoid nested rules that touch the same file inside an open update","Recreate the recorder from fresh content after any intermediate change"],"tags":["stale-content","update-recorder","race","schematics"],"backgroundTag":"content-has-mutated","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}