angular/angular-cli · error · Error

Invalid file replacement: ${JSON.stringify(fileReplacement)}

Error message

Invalid file replacement: ${JSON.stringify(fileReplacement)}

What it means

normalizeFileReplacement accepts each fileReplacements entry in one of two shapes: the current { replace, with } or the legacy { src, replaceWith }. If an entry matches neither shape, this error is thrown with the JSON of the offending object. It is a schema validation guarding against malformed or mixed-format replacement entries.

Source

Thrown at packages/angular_devkit/build_angular/src/utils/normalize-file-replacements.ts:62

  }

  return normalizedReplacement;
}

function normalizeFileReplacement(
  fileReplacement: FileReplacement,
  root: string,
): NormalizedFileReplacement {
  let replacePath: string;
  let withPath: string;
  if (fileReplacement.src && fileReplacement.replaceWith) {
    replacePath = fileReplacement.src;
    withPath = fileReplacement.replaceWith;
  } else if (fileReplacement.replace && fileReplacement.with) {
    replacePath = fileReplacement.replace;
    withPath = fileReplacement.with;
  } else {
    throw new Error(`Invalid file replacement: ${JSON.stringify(fileReplacement)}`);
  }

  return {
    replace: path.join(root, replacePath),
    with: path.join(root, withPath),
  };
}

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Rewrite the entry to the current format: { "replace": "<original file>", "with": "<replacement file>" }.
  2. Remove legacy keys src/replaceWith or migrate them to replace/with consistently.
  3. Validate the JSON structure of fileReplacements in angular.json — every element must have exactly the pair replace+with (all strings).

Example fix

// before (angular.json, mixed legacy keys)
"fileReplacements": [{ "src": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" }]
// after
"fileReplacements": [{ "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" }]
Defensive patterns

Strategy: type-guard

Validate before calling

// Reject malformed entries before the build
function validFileReplacement(fr) {
  return fr != null && typeof fr === 'object' &&
    ((typeof fr.replace === 'string' && typeof fr.with === 'string') ||
     (typeof fr.src === 'string' && typeof fr.replaceWith === 'string'));
}
schema.fileReplacements?.forEach(fr => { if (!validFileReplacement(fr)) throw new Error(`Bad fileReplacements entry: ${JSON.stringify(fr)}`); });

Type guard

function isFileReplacement(v) {
  return v != null && typeof v === 'object' &&
    ((typeof (v as any).replace === 'string' && typeof (v as any).with === 'string') ||
     (typeof (v as any).src === 'string' && typeof (v as any).replaceWith === 'string'));
}

Try / catch

try {
  await runBuild(schema);
} catch (err) {
  if (/^Invalid file replacement:/.test(err?.message ?? '')) {
    const bad = err.message.slice('Invalid file replacement: '.length);
    console.error(`Malformed fileReplacements entry: ${bad} — use { replace, with }.`);
    process.exitCode = 1;
  } else throw err;
}

Prevention

When it happens

Trigger: A fileReplacements array in angular.json containing an entry like { "src": "a.ts", "with": "b.ts" } or { "replace": "a.ts", "replaceWith": "b.ts" } (mixing old/new keys), or an entry missing one of the two required keys, or a plain string / null / wrong-typed element.

Common situations: Upgrading from old Angular CLI versions where fileReplacements used src/replaceWith and doing a partial rename in the config, IDE snippets with wrong keys, or programmatically generated configs (schematics/build scripts) emitting mixed fields.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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