{"record":{"id":"86e2536c1eac7486","repo":"angular/angular-cli","slug":"failed-to-decode-path-as-utf-8-text","errorCode":null,"errorMessage":"Failed to decode \"${path}\" as UTF-8 text.","messagePattern":"Failed to decode \"(.+?)\" as UTF-8 text\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/angular_devkit/schematics/src/tree/host-tree.ts","lineNumber":316,"sourceCode":"  readText(path: string): string {\n    const data = this.read(path);\n    if (data === null) {\n      throw new FileDoesNotExistException(path);\n    }\n\n    const decoder = new TextDecoder('utf-8', { fatal: true });\n\n    try {\n      // With the `fatal` option enabled, invalid data will throw a TypeError\n      return decoder.decode(data);\n    } catch (e) {\n      // The second part should not be needed. But Jest does not support instanceof correctly.\n      // See: https://github.com/jestjs/jest/issues/2549\n      if (\n        e instanceof TypeError ||\n        (e as NodeJS.ErrnoException).code === 'ERR_ENCODING_INVALID_ENCODED_DATA'\n      ) {\n        throw new Error(`Failed to decode \"${path}\" as UTF-8 text.`, { cause: e });\n      }\n      throw e;\n    }\n  }\n\n  readJson(path: string): JsonValue {\n    const content = this.readText(path);\n    const errors: ParseError[] = [];\n    const result = jsoncParse(content, errors, { allowTrailingComma: true });\n\n    // If there is a parse error throw with the error information\n    if (errors[0]) {\n      const { error, offset } = errors[0];\n      throw new Error(\n        `Failed to parse \"${path}\" as JSON. ${printParseErrorCode(error)} at offset: ${offset}.`,\n      );\n    }\n","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular_devkit/schematics/src/tree/host-tree.ts#L298-L334","documentation":"Thrown by HostTree.readText when the file's bytes are not valid UTF-8. It uses a TextDecoder with fatal:true, so invalid sequences raise a TypeError (or ERR_ENCODING_INVALID_ENCODED_DATA under Jest), which is wrapped into this error with the original kept as `cause`. The library throws because readText promises a string, and silently replacing bytes would hide data corruption.","triggerScenarios":"Calling tree.readText(path) on a binary file (images, fonts, .ico, .zip, compiled assets) or a file encoded in a non-UTF-8 charset (e.g. latin-1/GBK with high-byte characters).","commonSituations":"Schematics/rules that iterate all files in a directory and readText each one without filtering binary extensions; legacy projects with non-UTF-8 source files; reading assets committed to the tree by a copy operation.","solutions":["Filter to text-only extensions before calling readText, or use read() (returns Buffer) for unknown files.","Check decodability beforehand with new TextDecoder('utf-8', {fatal:true}).decode(buffer) in a try/catch.","Re-encode the offending file to UTF-8 in the repository, or detect its charset (e.g. with chardet/iconv-lite) and decode explicitly."],"exampleFix":"// before\nconst text = tree.readText(filePath);\n// after\nconst buf = tree.read(filePath);\nif (!buf) throw new Error('missing');\nlet text: string;\ntry {\n  text = new TextDecoder('utf-8', { fatal: true }).decode(buf);\n} catch {\n  return; // skip binary file\n}","handlingStrategy":"validation","validationCode":"const buf = tree.read(path);\nconst isText = buf !== null && (() => { try { new TextDecoder('utf-8', { fatal: true }).decode(buf); return true; } catch { return false; } })();","typeGuard":"function isUtf8Text(buf: Buffer): boolean {\n  try { new TextDecoder('utf-8', { fatal: true }).decode(buf); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  const text = tree.readText(path);\n} catch (e) {\n  if ((e as Error).message.includes('Failed to decode')) {\n    // treat as binary: use tree.read(path) Buffer instead\n  } else throw e;\n}","preventionTips":["Use read() (Buffer) unless you know the file is text","Filter by extension (skip images/fonts/binaries) before readText","Decode with fatal:true in a probe before committing to string processing","Normalize repository files to UTF-8 in CI (e.g. file/utf8 lint checks)"],"tags":["encoding","utf-8","binary-file","schematics"],"backgroundTag":"invalid-utf8-decode","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}