{"record":{"id":"e520a0df2bee8ae4","repo":"parcel-bundler/parcel","slug":"cannot-call-getcode-on-an-asset-with-a-dirty-ast","errorCode":null,"errorMessage":"Cannot call getCode() on an asset with a dirty AST. For transformers, implement canReuseAST() and check asset.isASTDirty.","messagePattern":"Cannot call getCode\\(\\) on an asset with a dirty AST\\. For transformers, implement canReuseAST\\(\\) and check asset\\.isASTDirty\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/core/src/UncommittedAsset.js","lineNumber":164,"sourceCode":"      return {size, hash: hash.finish()};\n    }\n\n    let hash;\n    if (typeof content === 'string') {\n      hash = hashString(content);\n      size = Buffer.byteLength(content);\n    } else {\n      hash = hashBuffer(content);\n      size = content.length;\n    }\n\n    await this.options.cache.setBlob(contentKey, content);\n    return {size, hash};\n  }\n\n  async getCode(): Promise<string> {\n    if (this.ast != null && this.isASTDirty) {\n      throw new Error(\n        'Cannot call getCode() on an asset with a dirty AST. For transformers, implement canReuseAST() and check asset.isASTDirty.',\n      );\n    }\n\n    let content = await this.content;\n    if (typeof content === 'string' || content instanceof Buffer) {\n      return content.toString();\n    } else if (content != null) {\n      this.content = bufferStream(content);\n      return (await this.content).toString();\n    }\n\n    invariant(false, 'Internal error: missing content');\n  }\n\n  async getBuffer(): Promise<Buffer> {\n    let content = await this.content;\n    if (content == null) {","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/parcel-bundler/parcel/blob/59484858a1a0bcbb71f74088956bb437a2db6505/packages/core/core/src/UncommittedAsset.js#L146-L182","documentation":"`getCode()` returns the asset's source. If the asset has an AST that has been modified (`isASTDirty === true`), reading `getCode()` would return stale code that doesn't reflect the AST changes. Parcel refuses to serve inconsistent data and instructs the transformer to either regenerate from the AST or declare it reusable.","triggerScenarios":"A transformer mutates `asset.ast` (marking it dirty) and then calls `asset.getCode()` before the AST has been regenerated.","commonSituations":"Custom transformers that edit the AST and then try to read the original source string; calling getCode in `postProcess` after AST mutation.","solutions":["Implement `canReuseAST()` and check `asset.isASTDirty` before touching the AST.","Regenerate code from the AST (via `generate`) before calling `getCode()`.","If you only need code, avoid mutating the AST, or set `ast` to null after extracting code."],"exampleFix":"// before\nasset.ast = transform(ast);\nconst code = await asset.getCode(); // throws\n\n// after\nasset.ast = transform(ast);\nconst {content} = await generate({asset, ast: asset.ast, options});\nconst code = content;","handlingStrategy":"validation","validationCode":"// Do not read code while the AST is dirty.\nif (asset.ast != null && asset.isASTDirty) {\n  await regenerateFromAST(asset);\n}\nconst code = await asset.getCode();","typeGuard":"function isASTClean(asset: {ast?: mixed, isASTDirty: boolean}): boolean {\n  return asset.ast == null || asset.isASTDirty === false;\n}","tryCatchPattern":null,"preventionTips":["Implement canReuseAST() and check isASTDirty before edits.","Regenerate code before getCode whenever you mutated the AST.","Clear the AST (set null) after you no longer need it."],"tags":["transformer","ast","asset"],"backgroundTag":null,"analyzedSha":"59484858a1a0bcbb71f74088956bb437a2db6505","analyzedAt":"2026-08-13T04:06:35.925Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}