angular/angular-cli · error

Failed to decode "${path}" as ${encoding} text.

Error message

Failed to decode "${path}" as ${encoding} text.

What it means

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.

Source

Thrown at packages/angular_devkit/schematics/src/tree/recorder.ts:35

  }
}

export class UpdateRecorderBase implements UpdateRecorder {
  protected _path: string;
  protected content: MagicString;

  constructor(
    private readonly data: Uint8Array,
    path: string,
    encoding = 'utf-8',
    private readonly bom = false,
  ) {
    let text;
    try {
      text = new TextDecoder(encoding, { fatal: true, ignoreBOM: false }).decode(data);
    } catch (e) {
      if (e instanceof TypeError) {
        throw new Error(`Failed to decode "${path}" as ${encoding} text.`, { cause: e });
      }

      throw e;
    }

    this._path = path;
    this.content = new MagicString(text);
  }

  static createFromFileEntry(entry: FileEntry): UpdateRecorderBase {
    const c0 = entry.content.byteLength > 0 && entry.content.readUInt8(0);
    const c1 = entry.content.byteLength > 1 && entry.content.readUInt8(1);
    const c2 = entry.content.byteLength > 2 && entry.content.readUInt8(2);

    // Check if we're BOM.
    if (c0 == 0xef && c1 == 0xbb && c2 == 0xbf) {
      return new UpdateRecorderBase(entry.content, entry.path, 'utf-8', true);
    } else if (c0 === 0xff && c1 == 0xfe) {

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Skip binary or undecodable files — check extension/content or catch this error and fall back to tree.overwrite with the original buffer.
  2. Verify the file is valid UTF-8 (or the expected encoding) before beginning an update.
  3. Explicitly pass the correct encoding when constructing the recorder instead of relying on defaults.

Example fix

// before
const recorder = tree.beginUpdate('/assets/logo.png');
// after
try {
  const recorder = tree.beginUpdate('/assets/logo.png');
} catch (e) {
  if (/Failed to decode/.test(String(e))) {
    return; // skip binary file
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

function isDecodable(buf: Buffer, encoding = 'utf-8'): boolean {
  try { new TextDecoder(encoding, { fatal: true }).decode(buf); return true; }
  catch { return false; }

Try / catch

try {
  const recorder = tree.beginUpdate(path);
} catch (e) {
  if (/^Failed to decode/.test(String(e))) {
    return; // skip binary/undecodable file
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/727ba3f39eacbbfd. Report an issue: GitHub.