{"record":{"id":"b7b619e5c91e4fc3","repo":"angular/angular-cli","slug":"content-at-path-this-path-has-changed-between","errorCode":null,"errorMessage":"Content at path \"${this.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/recorder.ts","lineNumber":96,"sourceCode":"  }\n\n  insertRight(index: number, content: Buffer | string): UpdateRecorder {\n    this._assertIndex(index);\n    this.content.appendRight(index, content.toString());\n\n    return this;\n  }\n\n  remove(index: number, length: number): UpdateRecorder {\n    this._assertIndex(index);\n    this.content.remove(index, index + length);\n\n    return this;\n  }\n\n  apply(content: Buffer): Buffer {\n    if (!content.equals(this.data)) {\n      throw new ContentHasMutatedException(this.path);\n    }\n\n    // Schematics only support writing UTF-8 text\n    const result = Buffer.from((this.bom ? '\\uFEFF' : '') + this.content.toString(), 'utf-8');\n\n    return result;\n  }\n}\n","sourceCodeStart":78,"sourceCodeEnd":105,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular_devkit/schematics/src/tree/recorder.ts#L78-L105","documentation":"The recorder buffers staged changes against a snapshot of the file's content (this.data). On apply(), if the underlying content passed in no longer equals that snapshot, the file mutated mid-update (ContentHasMutatedException). Schematics requires a stable buffer so the recorded diff applies to exactly the bytes it was created from.","triggerScenarios":"Calling tree.apply() with a Buffer that differs from what the UpdateRecorderBase captured at creation; mutating the file buffer (or the underlying host file) between creating the recorder from tree.beginUpdate(path) and calling recorder.apply()/commit.","commonSituations":"Two recorders opened on the same file where one commit rewrites the bytes; a rule or host transform rewrites the file during the same tree pass; async code mutating the buffer before commit; tooling (e.g. a format step) touching the file between beginUpdate and commit.","solutions":["Create the recorder, apply edits, and commit immediately without intervening mutations to that file's content","Ensure only one UpdateRecorder per file is active at a time; merge edits into a single recorder instead","Re-create the recorder after any code path rewrites the file (re-read from the fresh tree content)","If you must transform content, do it before beginUpdate or via tree.overwrite with the fully transformed buffer"],"exampleFix":"// before\nconst recorder = tree.beginUpdate('src/app.ts');\nsomeOtherRuleThatRewritesAppTs(tree); // mutates content mid-update\nrecorder.insertLeft(0, '// hi');\ntree.commitUpdate(recorder); // throws ContentHasMutatedException\n// after\nconst recorder = tree.beginUpdate('src/app.ts');\nrecorder.insertLeft(0, '// hi');\ntree.commitUpdate(recorder);\nsomeOtherRuleThatRewritesAppTs(tree); // run after commit","handlingStrategy":"validation","validationCode":"const recorder = tree.beginUpdate(path);\n// ...edits...\n// before commit, ensure content unchanged:\nconst current = tree.read(path);\nif (!current || !current.equals(initialSnapshot)) throw new Error('File changed during update');\ntree.commitUpdate(recorder);","typeGuard":null,"tryCatchPattern":"try {\n  tree.commitUpdate(recorder);\n} catch (e) {\n  if (/has changed between the start and the end/.test(String(e))) {\n    // re-open a fresh recorder against current content and retry edits\n  } else throw e;\n}","preventionTips":["Open and commit each recorder in one tight, synchronous block","Never hold two recorders for the same file at once","Do not mutate file buffers between beginUpdate and commitUpdate","Re-read the tree after any external process may have rewritten files"],"tags":["schematics","tree-mutation","angular","recorder"],"backgroundTag":"tree-content-mutated","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}