Fix Invalid options object: allowedHosts[0] with CRA proxy
Find which of the two triggers crashes npm start, pick a fix that still proxies your API calls, and avoid the http-proxy-middleware v3 path trap.
TL;DR#
react-scripts start (Create React App 5) crashes with this schema error when two things are true at once: package.json has a "proxy" field, and react-scripts cannot work out a private LAN address for the dev server. That happens when HOST names a specific host (anything other than 0.0.0.0 or ::), or when the machine has no private IPv4 address (no network, or only a public IP). In both cases it hands webpack-dev-server an allowedHosts list whose only item is undefined. The fix: unset HOST if you did not mean to set it, or move the proxy into src/setupProxy.js with http-proxy-middleware version 2. Only the first keeps the dev server's host check, which protects your backend from DNS rebinding.
The error, as npm start prints it with react-scripts 5.0.1:
Attempting to bind to HOST environment variable: localhost
If this was unintentional, check that you haven't mistakenly set it in your shell.
Learn more here: https://cra.link/advanced-config
Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.allowedHosts[0] should be a non-empty string.The Stack Overflow question shows the same two lines under yarn start. The asker's package.json pins "react-scripts": "5.0.0" and the app starts again as soon as "proxy": "http://localhost:6000" is deleted.
Why react-scripts builds an invalid allowedHosts#
Three pieces of Create React App's source explain the crash. All links point at the same commit.
start.jscallsprepareUrls()with the host to bind (theHOSTvariable, or0.0.0.0when it is unset). It then passes the result's LAN address to the dev server config:createDevServerConfig(proxyConfig, urls.lanUrlForConfig).prepareUrls()only fills in that LAN address when the host is0.0.0.0or::. Even then, it keeps the address only if it falls in one of the three private IPv4 ranges. Any other host, a public IP or no IPv4 at all leaves itundefined.webpackDevServer.config.jsturns the host check off unless a proxy is configured:allowedHosts: disableFirewall ? 'all' : [allowedHost], wheredisableFirewallis true when there is no proxy or whenDANGEROUSLY_DISABLE_HOST_CHECKis'true'.
With a proxy and no LAN address, the dev server receives allowedHosts: [undefined]. react-scripts 5.0.0 and 5.0.1 both depend on webpack-dev-server ^4.6.0 (npm registry). The version 4 options schema (v4.15.2 options.json) requires every allowedHosts item to be a string of at least one character. Validation fails before the server binds a port.
The host check exists for a reason. The CRA proxy documentation says that enabling proxy opts you into stricter host checks, to protect the backend from DNS rebinding attacks. The same page suggests setting HOST to your public development host to get past "Invalid Host header". Combined with proxy, that suggestion now triggers this crash. The bug is tracked in create-react-app#11762, opened against 5.0.0 and still open. 5.0.1 is still the latest tag on npm, and the repository README marks Create React App as deprecated.
Reproducing both triggers#
Both paths were reproduced on 20 October 2026 in a node:20-alpine container (Node 20.20.2, react-scripts 5.0.1, webpack-dev-server 4.15.2). The test app is a minimal CRA app with "proxy": "http://localhost:6000" and a small JSON backend on port 6000.
With HOST=localhost, npm start fails with the output above. A HOST set to the container's own hostname fails the same way. That is the setting the CRA docs suggest for "Invalid Host header".
As a negative control, the same app with no HOST starts and proxies, because the container's bridge address (172.17.0.3) is private:
On Your Network: http://172.17.0.3:3000
{"from":"backend:6000","path":"/api/todos"}The second trigger appears once the same container is disconnected from its network. address.ip() (the helper prepareUrls() calls) then returns nothing, and npm start crashes with no HOST set at all:
$ node -p "require(\"address\").ip()"
undefined
Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.allowedHosts[0] should be a non-empty string.The Stack Overflow asker shows no HOST, so you cannot tell from the question which trigger hit them. Check yours first:
echo "HOST=$HOST"
grep -s HOST .env .env.local .env.development .env.development.localreact-scripts prints "Attempting to bind to HOST environment variable" whenever HOST is set. If the value is a hostname or a specific address, you have the first trigger. If HOST is unset, or set to 0.0.0.0 or ::, look at the network instead: an offline machine, or one whose only IPv4 address is public.
Fix#
-
Unset an unintended
HOST. Remove the line from.env(or the shell profile), then start again:bashunset HOST npm startThis is the negative-control run above: the proxy keeps working. It only helps with the first trigger and only if you do not need a specific bind address.
-
Move the proxy into
src/setupProxy.js(the accepted answer, and CRA's documented "Configuring the Proxy Manually"). Delete the"proxy"line frompackage.json, then install the middleware. Pin major version 2, the line react-scripts' own webpack-dev-server uses:bashnpm install http-proxy-middleware@2 --savejs// src/setupProxy.js const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function (app) { app.use( '/api', createProxyMiddleware({ target: 'http://localhost:6000', changeOrigin: true, }) ); };react-scripts loads this file with
require()when the dev server starts; you do not import it anywhere. Becausepackage.jsonno longer has aproxy,disableFirewallis true andallowedHostsbecomes'all'. So this fix also switches off the host check that theproxyfield would have turned on. That is the trade-off the docs warn about. The threat is DNS rebinding: while the dev server runs, a malicious page you open in your own browser can send requests to it, and through the proxy to your backend. No network setting prevents that. Stop the dev server when you are not using it, and if you do not need a specificHOST, prefer fix 1, which keeps the check on. -
Or keep
proxyand setDANGEROUSLY_DISABLE_HOST_CHECK=truein.env.development.local. This works with either trigger, and the reproduction proxied/api/todosnormally withHOST=localhoststill set. The CRA docs call it dangerous and "exposes your machine to remote code execution from malicious websites": any website you visit while the dev server runs can reach your backend through it. Turn the variable off as soon as you no longer need it, and prefer fix 1 or fix 2.
Verify the fix#
Start the dev server, then request an API path with a non-HTML Accept header. The CRA proxy only forwards requests without text/html in Accept:
curl -s -H 'Accept: application/json' http://localhost:3000/api/todosThe backend's JSON should come back. In the reproduction (which used busybox wget with the same Accept header), the setupProxy fix with http-proxy-middleware 2.0.10 returned:
[HPM] Proxy created: / -> http://localhost:6000
{"from":"backend:6000","path":"/api/todos"}One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Two fixes that start the server but break the proxy#
npm install http-proxy-middleware without a version. On Node 20 this installed 3.0.7. Version 3 no longer rewrites req.url, so when the middleware is mounted with app.use('/api', …) the backend receives the path without its mount prefix:
`-- http-proxy-middleware@3.0.7
{"from":"backend:6000","path":"/todos"}The v3 migration guide says the mount path must now go in the target (target: 'http://localhost:6000/api'). The current latest on npm is version 4. Its release notes list breaking changes of their own, including a minimum of Node 22.15.0 and an ESM-only package. Pinning @2 keeps the code from the CRA docs and the accepted answer working as written.
Wrapping proxy in an "options" object (the second answer on the question). react-scripts reads require(paths.appPackageJson).proxy, the top-level key only. So the wrapper simply hides the proxy, and the server starts because allowedHosts falls back to 'all'. With HOST=localhost set, the reproduction started cleanly and the API call failed:
$ wget -qO- -S --header=Accept:application/json http://[::1]:3000/api/todos
HTTP/1.1 404 Not FoundOne more detail from the reproduction: with HOST=localhost on Node 20, the dev server listened on ::1, so a request to 127.0.0.1:3000 was refused. If curl fails after a successful start, try localhost or [::1] before you suspect the proxy.
When the browser shows a different error#
Once npm start runs, the next errors are usually in the browser, not the terminal. A page that loads with "Invalid Host header" means the host check is on and you are browsing from a hostname it does not know (a cloud editor, a custom domain). Setting HOST to that name now crashes with proxy, so use the setupProxy fix. If you drop the proxy entirely and call the API on its own port, the browser enforces CORS instead; the CORS fix for calls from localhost:3000 explains which header the backend must send.
If the app runs in Docker, the network trigger shows up in a different form. A container on the default bridge network gets a private address, but --network none, or a custom network whose subnet is outside the private ranges, leaves react-scripts without one. For two other CRA-in-Docker problems, see the hot reload fix for WSL2 and the missing public/index.html fix. An old react-scripts 4 project upgraded to a recent Node can hit error:0308010C:digital envelope routines::unsupported first. That page covers the webpack 4 hash and the react-scripts 5 upgrade that removes it, and once the project is on react-scripts 5, a proxy field can then produce the allowedHosts crash above.
Whichever fix you choose, it is a workaround in a tool that will not get another release. For a new project, the CRA README points to the frameworks listed on react.dev. Until you migrate, setupProxy.js with http-proxy-middleware 2 is the fix that keeps both the server and the proxy working.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix error:0308010C digital envelope routines::unsupported
Find which part of your build still asks for MD4, apply the one-line workaround to unblock a deploy, then remove it with a webpack or react-scripts upgrade.
Fix secretOrPrivateKey must have a value in NestJS JWT
Reproduced on @nestjs/jwt 12.0.3 and 10.0.3: why a configured JwtModule still signs with an empty key, why two popular answers fall short, and the .env load-order variant of the same error.
Vite server running but not working on localhost: 3 causes
Tell in one request whether Vite itself answered 404 or another server did, then move index.html, pin the host or free the port, and confirm it with curl.


