webpack/webpack · error · Error

optimization.concatenateModules can't be used with cacheUnaf

Error message

optimization.concatenateModules can't be used with cacheUnaffected as module concatenation is a global effect

What it means

ModuleConcatenationPlugin inlines multiple modules into a single concatenated module, a graph-global transformation: a module's concatenated form depends on its neighbors. experiments.cacheUnaffected requires per-module independence, so the combination is invalid. At the compilation hook, if compilation.moduleMemCaches is set, the plugin throws before doing any work.

Source

Thrown at lib/optimize/ModuleConcatenationPlugin.js:109

 * Format bailout reason.
 * @param {string} msg message
 * @returns {string} formatted message
 */
const formatBailoutReason = (msg) => `ModuleConcatenation bailout: ${msg}`;

const PLUGIN_NAME = "ModuleConcatenationPlugin";

class ModuleConcatenationPlugin {
	/**
	 * Applies the plugin by registering its hooks on the compiler.
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const { _backCompat: backCompat } = compiler;
		compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
			if (compilation.moduleMemCaches) {
				throw new Error(
					"optimization.concatenateModules can't be used with cacheUnaffected as module concatenation is a global effect"
				);
			}
			const moduleGraph = compilation.moduleGraph;
			/** @type {Map<Module, string | ((requestShortener: RequestShortener) => string)>} */
			const bailoutReasonMap = new Map();

			/**
			 * Sets bailout reason.
			 * @param {Module} module the module
			 * @param {string | ((requestShortener: RequestShortener) => string)} reason the reason
			 */
			const setBailoutReason = (module, reason) => {
				setInnerBailoutReason(module, reason);
				moduleGraph
					.getOptimizationBailout(module)
					.push(
						typeof reason === "function"

View on GitHub (pinned to 318421ea8a)

Solutions

  1. Disable concatenation: optimization.concatenateModules = false.
  2. Or disable the experiment: experiments.cacheUnaffected = false.
  3. Disabling concatenation is the supported way to keep cacheUnaffected; expect a modest increase in module count / runtime overhead.

Example fix

// before
module.exports = {
  mode: 'production', // concatenateModules defaults to true
  experiments: { cacheUnaffected: true }
};
// after
module.exports = {
  mode: 'production',
  optimization: { concatenateModules: false },
  experiments: { cacheUnaffected: true }
};
Defensive patterns

Strategy: validation

Validate before calling

function assertCacheUnaffectedCompat(config) {
  const cu = config.experiments && config.experiments.cacheUnaffected;
  const concat = config.optimization && config.optimization.concatenateModules;
  if (cu && concat !== false) {
    throw new Error('experiments.cacheUnaffected requires optimization.concatenateModules: false');
  }
}

Prevention

When it happens

Trigger: experiments.cacheUnaffected: true combined with optimization.concatenateModules: true (concatenateModules defaults to true in production mode, so this trips unless explicitly disabled).

Common situations: Turning on cacheUnaffected in a production config where concatenateModules is on by default. Adopting the cache experiment for dev-loop speed without adjusting optimization defaults.

Related errors


AI-assisted analysis of webpack/webpack@318421ea8a (2026-08-03). Data as JSON: /data/errors/e5b2ae8fd5ea5689.json. Report an issue: GitHub.