angular/angular-cli · error
Failed to decode "${path}" as UTF-8 text.
Error message
Failed to decode "${path}" as UTF-8 text. What it means
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.
Source
Thrown at packages/angular_devkit/schematics/src/tree/host-tree.ts:316
readText(path: string): string {
const data = this.read(path);
if (data === null) {
throw new FileDoesNotExistException(path);
}
const decoder = new TextDecoder('utf-8', { fatal: true });
try {
// With the `fatal` option enabled, invalid data will throw a TypeError
return decoder.decode(data);
} catch (e) {
// The second part should not be needed. But Jest does not support instanceof correctly.
// See: https://github.com/jestjs/jest/issues/2549
if (
e instanceof TypeError ||
(e as NodeJS.ErrnoException).code === 'ERR_ENCODING_INVALID_ENCODED_DATA'
) {
throw new Error(`Failed to decode "${path}" as UTF-8 text.`, { cause: e });
}
throw e;
}
}
readJson(path: string): JsonValue {
const content = this.readText(path);
const errors: ParseError[] = [];
const result = jsoncParse(content, errors, { allowTrailingComma: true });
// If there is a parse error throw with the error information
if (errors[0]) {
const { error, offset } = errors[0];
throw new Error(
`Failed to parse "${path}" as JSON. ${printParseErrorCode(error)} at offset: ${offset}.`,
);
}
View on GitHub (pinned to bb72145f9a)
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.
Example fix
// before
const text = tree.readText(filePath);
// after
const buf = tree.read(filePath);
if (!buf) throw new Error('missing');
let text: string;
try {
text = new TextDecoder('utf-8', { fatal: true }).decode(buf);
} catch {
return; // skip binary file
} Defensive patterns
Strategy: validation
Validate before calling
const buf = tree.read(path);
const isText = buf !== null && (() => { try { new TextDecoder('utf-8', { fatal: true }).decode(buf); return true; } catch { return false; } })(); Type guard
function isUtf8Text(buf: Buffer): boolean {
try { new TextDecoder('utf-8', { fatal: true }).decode(buf); return true; } catch { return false; }
} Try / catch
try {
const text = tree.readText(path);
} catch (e) {
if ((e as Error).message.includes('Failed to decode')) {
// treat as binary: use tree.read(path) Buffer instead
} else throw e;
} Prevention
- 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)
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to decode "${path}" as ${encoding} text.
- schematicName cannot be undefined.
- The "not" keyword is not supported in JSON Schema.
- Could not find (/.angular.json)
- Unknown schematics built-in module '${id}' requested from sc
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/86e2536c1eac7486.
Report an issue: GitHub.