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 ejectdumped webpack config files that violate the schema expected by the pinned webpack version insidenode_modules, causing an immediate hard crash on every subsequentnpm 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.jsand 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:
- Every environment breaks simultaneously. The config is committed to source control post-eject. Every developer, every pipeline stage, every Dockerfile that runs
npm run buildhits the same wall. - Version lock-in trap. CRA's internal webpack is hoisted under
react-scripts/node_modules. After eject,package.jsongets a directwebpackentry. Ifnpm installresolves 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. - Silent config corruption. Properties like
loadervsuse,queryvsoptions, andloaders(webpack 3 array syntax) vsrulesare silently carried over from outdated CRA internals. The ejected file looks syntactically valid JavaScript but is semantically wrong for the installed webpack version. - 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.