{"record":{"id":"727ba3f39eacbbfd","repo":"angular/angular-cli","slug":"failed-to-decode-path-as-encoding-text","errorCode":null,"errorMessage":"Failed to decode \"${path}\" as ${encoding} text.","messagePattern":"Failed to decode \"(.+?)\" as (.+?) text\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/angular_devkit/schematics/src/tree/recorder.ts","lineNumber":35,"sourceCode":"  }\n}\n\nexport class UpdateRecorderBase implements UpdateRecorder {\n  protected _path: string;\n  protected content: MagicString;\n\n  constructor(\n    private readonly data: Uint8Array,\n    path: string,\n    encoding = 'utf-8',\n    private readonly bom = false,\n  ) {\n    let text;\n    try {\n      text = new TextDecoder(encoding, { fatal: true, ignoreBOM: false }).decode(data);\n    } catch (e) {\n      if (e instanceof TypeError) {\n        throw new Error(`Failed to decode \"${path}\" as ${encoding} text.`, { cause: e });\n      }\n\n      throw e;\n    }\n\n    this._path = path;\n    this.content = new MagicString(text);\n  }\n\n  static createFromFileEntry(entry: FileEntry): UpdateRecorderBase {\n    const c0 = entry.content.byteLength > 0 && entry.content.readUInt8(0);\n    const c1 = entry.content.byteLength > 1 && entry.content.readUInt8(1);\n    const c2 = entry.content.byteLength > 2 && entry.content.readUInt8(2);\n\n    // Check if we're BOM.\n    if (c0 == 0xef && c1 == 0xbb && c2 == 0xbf) {\n      return new UpdateRecorderBase(entry.content, entry.path, 'utf-8', true);\n    } else if (c0 === 0xff && c1 == 0xfe) {","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular_devkit/schematics/src/tree/recorder.ts#L17-L53","documentation":"UpdateRecorderBase's constructor decodes the file buffer with a fatal TextDecoder; if the bytes are not valid text for the chosen encoding (e.g. UTF-8), it throws this Error with the decoding TypeError as cause. It protects the recorder from building text edits over undecodable content.","triggerScenarios":"Calling tree.beginUpdate(path) where the file contains bytes invalid for the supplied encoding (binary files, wrong-charset files, corrupted content); passing a bad encoding string to a recorder constructor.","commonSituations":"Running codemods/schematics over binary assets (images, fonts, .ico), files saved with unexpected encodings (e.g. UTF-16), or locking/checkout artifacts; also editing files with BOM/encoding mismatches.","solutions":["Skip binary or undecodable files — check extension/content or catch this error and fall back to tree.overwrite with the original buffer.","Verify the file is valid UTF-8 (or the expected encoding) before beginning an update.","Explicitly pass the correct encoding when constructing the recorder instead of relying on defaults."],"exampleFix":"// before\nconst recorder = tree.beginUpdate('/assets/logo.png');\n// after\ntry {\n  const recorder = tree.beginUpdate('/assets/logo.png');\n} catch (e) {\n  if (/Failed to decode/.test(String(e))) {\n    return; // skip binary file\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"function isDecodable(buf: Buffer, encoding = 'utf-8'): boolean {\n  try { new TextDecoder(encoding, { fatal: true }).decode(buf); return true; }\n  catch { return false; }","typeGuard":null,"tryCatchPattern":"try {\n  const recorder = tree.beginUpdate(path);\n} catch (e) {\n  if (/^Failed to decode/.test(String(e))) {\n    return; // skip binary/undecodable file\n  }\n  throw e;\n}","preventionTips":["Filter out binary extensions (.png, .ico, .woff) before text edits","Pre-validate buffers with a fatal TextDecoder","Specify the expected encoding explicitly when constructing recorders","Investigate e.cause TypeError details for encoding mismatches"],"tags":["encoding","text-decoding","schematics","recorder"],"backgroundTag":"text-decoding-failed","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}