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
- Rewrite the entry to the current format: { "replace": "<original file>", "with": "<replacement file>" }.
- Remove legacy keys src/replaceWith or migrate them to replace/with consistently.
- 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
- After migrating from legacy src/replaceWith, remove old keys entirely rather than mixing formats.
- Type angular.json fileReplacements with a discriminated schema so editors flag wrong keys.
- Validate config with the workspace schema (ng build validates) before custom tooling consumes it.
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
- File replacement (with) does not exist
- File replacement (replace) does not exist
- Unsupported package manager: "${name}"
- The configured package manager, '${this.descriptor.binary}',
- Project "${project}" does not exist.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/04de496b5c8621be.
Report an issue: GitHub.