Initializing Enclave...

How to Fix CRA 'react-scripts eject' Failing with 'Invalid configuration object' in Webpack

Threat/Impact Level: HIGH | Downtime Risk: HIGH | Time to Fix: 15–45 mins


TL;DR

  • What broke: react-scripts eject dumped webpack config files that violate the schema expected by the pinned webpack version inside node_modules, causing an immediate hard crash on every subsequent npm start / npm run build.
  • How to fix it: Identify the offending property path printed in the webpack validation error, cross-reference it against the webpack version CRA ejected with, and correct the schema mismatch in config/webpack.config.js.
  • Fast path: Use our Client-Side Sandbox below to auto-refactor this — paste your webpack.config.js and the full error stack; it redacts secrets locally and outputs the corrected diff.

The Incident (What does the error mean?)

The raw crash looks like this:

Invalid configuration object. Webpack has been initialized using a configuration
object that does not match the API schema.
 - configuration.module.rules[3] has an unknown property 'query'.
   Did you mean to use 'options' instead?
 - configuration.output.filename: The provided value "static/js/[name].[contenthash:8].js"
   is not a valid filename template string.

Eject writes static copies of CRA's internal webpack configs into config/webpack.config.js and config/webpackDevServer.config.js. The moment eject completes, you own those files. If the CRA version you ejected from was pinned to webpack 4 but a transitive dependency pulled in a webpack 5 peer, or vice versa, webpack's strict JSON-schema validator (ajv) rejects the config object at startup. The build pipeline is completely dead — npm start, npm run build, and CI all fail instantly.


The Attack Vector / Blast Radius

This is not a security exploit vector, but the blast radius in a CI/CD pipeline is total:

  1. Every environment breaks simultaneously. The config is committed to source control post-eject. Every developer, every pipeline stage, every Dockerfile that runs npm run build hits the same wall.
  2. Version lock-in trap. CRA's internal webpack is hoisted under react-scripts/node_modules. After eject, package.json gets a direct webpack entry. If npm install resolves a different semver than what CRA was using internally, the schema mismatch is non-deterministic across machines — it works on one developer's laptop and fails in CI.
  3. Silent config corruption. Properties like loader vs use, query vs options, and loaders (webpack 3 array syntax) vs rules are silently carried over from outdated CRA internals. The ejected file looks syntactically valid JavaScript but is semantically wrong for the installed webpack version.
  4. Irreversibility. Eject is a one-way operation. You cannot un-eject. A botched eject with a broken config means manual surgery on a 400+ line generated file with zero rollback path unless you have a clean Git branch.

How to Fix It

Step 1 — Pin the exact webpack version CRA was using before eject

Before touching the config, lock the webpack version to what CRA internally used:

# Check what version react-scripts was bundling
cat node_modules/react-scripts/node_modules/webpack/package.json | grep '"version"'
# e.g., outputs: "version": "5.88.2"

# Pin that exact version in your root package.json
npm install [email protected] --save-exact

Step 2 — Fix the schema violations in config/webpack.config.js

Common violation 1: query renamed to options in webpack 4+

  module: {
    rules: [
      {
        test: /\.(js|mjs|jsx|ts|tsx)$/,
        loader: require.resolve('babel-loader'),
-       query: {
+       options: {
          presets: [require.resolve('babel-preset-react-app')],
        },
      },
    ],
  },

Common violation 2: loaders array syntax replaced by use in webpack 4+

  {
    test: /\.css$/,
-   loaders: [
-     require.resolve('style-loader'),
-     require.resolve('css-loader'),
-   ],
+   use: [
+     require.resolve('style-loader'),
+     require.resolve('css-loader'),
+   ],
  },

Common violation 3: contenthash template invalid for webpack 4 (requires chunkhash instead)

  output: {
-   filename: 'static/js/[name].[contenthash:8].js',
-   chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
+   filename: 'static/js/[name].[chunkhash:8].js',
+   chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
  },

Note: contenthash IS valid in webpack 5. Only apply the chunkhash fix if you are locked to webpack 4.

Common violation 4: optimization.splitChunks.cacheGroups entry missing required chunks property

  optimization: {
    splitChunks: {
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
+         chunks: 'all',
          name: 'vendors',
          enforce: true,
        },
      },
    },
  },

Enterprise Best Practice — Validate the config before committing

After any edit to config/webpack.config.js, run webpack's built-in schema validation dry-run before pushing:

# Dry-run validation without starting a build
node -e "
  const webpack = require('webpack');
  const config = require('./config/webpack.config')('production');
  const compiler = webpack(config);
  console.log('Config is valid.');
" 2>&1

If the schema is still broken, webpack prints the exact property path that fails. Fix, repeat.


💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

1. Lock webpack with --save-exact and commit package-lock.json

Never allow floating semver on webpack after eject. A ^5.0.0 range in package.json is a time bomb.

2. Add a webpack config validation step as a pre-commit hook

# .husky/pre-commit
npm run validate:webpack
// package.json scripts
"validate:webpack": "node -e \"require('webpack')(require('./config/webpack.config')('production')); console.log('OK');\""

3. Pin Node.js version in CI to match local dev

webpack's ajv schema validation behavior has changed across Node versions. Use .nvmrc or engines in package.json and enforce it in your pipeline:

# GitHub Actions
steps:
  - uses: actions/setup-node@v4
    with:
      node-version-file: '.nvmrc'
      cache: 'npm'

4. Use webpack-config-validator or @webpack-cli/configtest in CI

# webpack-cli built-in config test (webpack 5 only)
npx webpack configtest config/webpack.config.js

Add this as a mandatory CI gate before any npm run build step. A failing config test should block the PR, not the deployment.

5. Consider migrating off CRA entirely

If you are ejecting, you are already past CRA's intended use case. Vite with @vitejs/plugin-react eliminates this entire class of problem — its config is explicit, versioned, and schema-validated by TypeScript types rather than runtime AJV checks.

Related Diagnostics

"Part of the Syntax Utility Matrix."

View all 153 Syntax Tools →