net::ERR_CONNECTION_REFUSED
Nothing was listening at that address and port, usually because the server isn’t running or the app is calling the wrong port.
Also appears as
- This site can’t be reached localhost refused to connect.
- Firefox can’t establish a connection to the server at localhost:3000.
- Error: connect ECONNREFUSED 127.0.0.1:3000
- [vite] http proxy error: /api/items AggregateError [ECONNREFUSED]:
Prompt to fix it
My app logs "net::ERR_CONNECTION_REFUSED" for requests to our API. Work out which URL and port the frontend calls and which server should answer there. Check whether our dev scripts start that server, whether it crashes on startup, and whether the port matches, including the Vite proxy and any API URL environment variable. Fix the mismatch. If the production build still points at localhost, read the API URL from an environment variable instead. Tell me the exact commands to start everything locally, and don’t add retries to hide the error.
Paste into Layerwise or any AI coding tool.
What it means
“Connection refused” is a fast, definite answer: the browser reached the machine, and no program on it was accepting connections on that port. With localhost, that machine is your own computer, so the server you meant to call isn’t running, crashed, or listens on a different port.
Many projects run two servers: the frontend dev server (Vite on 5173, Next.js on 3000) and a separate API. Starting one without the other, or an API that crashed on startup, gives exactly this error. The terminal where the API should be running usually shows the real problem.
Ports also move. When a port is taken, Vite and Next.js pick the next free one, such as 5174 or 3001, while the frontend keeps calling the old one. And if this happens only on the published site, the code still calls localhost, which points at each visitor’s own computer.
Common causes
- The API or backend server isn’t running, or it crashed on startup with an error in its terminal.
- The frontend calls a different port than the server uses, often after a dev server moved to the next free port.
- The published app still calls
localhost, so requests go to each visitor’s own computer. - The Vite dev proxy sends
/apito a port where nothing is running. - The server runs in a Docker container that doesn’t publish its port to your computer.
How to fix it
- Note the URL and port in the failed request, then open the terminal where that server should be running.
- Start the server, for example with
npm run devin the API folder, and read its startup output for errors and the port it chose. - Make the frontend’s API URL, or the
server.proxytarget invite.config.ts, match that port. - Run
curl http://localhost:3000/api/itemsin a terminal. A refusal there confirms the server side is the problem. - For the published site, replace
localhostwith the deployed API’s URL through an environment variable.
Example fix
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
proxy: {
// Must match the port the API server prints when it starts.
'/api': 'http://localhost:3000'
}
}
});Related errors
All errorsFailed to fetch
The browser never got a usable response: the server was unreachable, or the browser blocked the request or its reply.
EADDRINUSE: address already in use
Another program is already listening on the port your server wants, often an old copy of the same dev server that never stopped.
Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Your code expected JSON, but the server sent back an HTML page, usually a 404 page or your app’s own index.html.
Blocked by CORS policy
The browser hid a response from another site because that server never said your site is allowed to read it.
Build with an agent that checks its work
The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.