Geonode logo
Network errors

How to Fix ECONNREFUSED (Connection Refused)

Learn which machine refused you from the message, then apply three fixes, one with cURL, Python and Node.js code.

Updated

TL;DR

ECONNREFUSED means the host at the ip:port in the message rejected the connection because no program there accepts it; when your client uses an HTTP proxy, that host is always the proxy, never the site. Start the service, or point your code at the host and port it listens on.

What ECONNREFUSED looks like in each client

Where a line shows an address and port, it is the one that client tried.

WhereWhat you see
Node.js http moduleError: connect ECONNREFUSED 127.0.0.1:8080
Node.js fetch (undici)TypeError: fetch failed ... [cause]: Error: connect ECONNREFUSED 127.0.0.1:8080
axios, as console.log prints itAxiosError: connect ECONNREFUSED 127.0.0.1:8080
Node.js 20 or later, host name localhostAggregateError [ECONNREFUSED]:
Vite dev server, server.proxy target down[vite] http proxy error: /api/users
Python requests on macOS (urllib3 2.6 or later)requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: / (Caused by NewConnectionError("HTTPConnection(host='localhost', port=8080): Failed to establish a new connection: [Errno 61] Connection refused"))
curlcurl: (7) Failed to connect to localhost port 8080 after 0 ms: Couldn't connect to server

Why this happens

Nothing on that machine was listening on the port your code tried.

Most often the server has not started or has crashed, so its port is closed and the host answers your connection request with a TCP reset.

Diagnose your ECONNREFUSED first

These checks tell you which machine refused and why; the first one needs only the error text.

  • Read the address after ECONNREFUSED; 127.0.0.1 or ::1 means the closed port is on your own computer, and any other means a remote one.

  • Run lsof -nP -iTCP:8080 -sTCP:LISTEN, or netstat -ano | findstr :8080 on Windows; no output means nothing listens on that port.

  • Compare the address in that lsof line with the error's; if one is [::1] and the other 127.0.0.1, client and server disagree.

  • If the error names a port you never set, run env | grep -i proxy; a leftover proxy variable sends curl, axios and Python there.

  • Inside a container, run the same request from your computer; if only the container fails, localhost there is the container's own loopback.

Solutions ranked by effectiveness

Most refusals end with the first fix; the other two cover address mismatches and slow-starting services.

  1. Most common fix

    Start the service on the port you call

    Applies when the lsof check comes back empty. Start the program and copy the port it prints at startup, which can differ from the one in your config.

    1. Start the server or database, then wait for the line that names its port.

    2. Copy that exact port into your client URL, proxy target or connection string.

    3. If the program exits at once, fix the error its log shows first.

    4. For a proxy, paste its host and port again from your provider's dashboard.

  2. Check next

    Match the client to the server's address

    Applies when a server is running, but bound to an IP your client does not dial, for example IPv6 ::1 versus IPv4 127.0.0.1.

    1. If the server listens on [::1] only, use the name localhost, not 127.0.0.1.

    2. Or pin the server to one address, for example vite --host 127.0.0.1.

    3. To accept other machines on a trusted network, bind it to 0.0.0.0 instead.

    4. From a container, call services by name (db:5432) and Docker Desktop's host at host.docker.internal.

  3. For developers

    Retry only while the service starts

    Applies when tests or a CI job call a database or API before it accepts connections. Retry refusals only, with a pause and a cap, then stop with a clear error.

    curl --retry 10 --retry-delay 2 --retry-connrefused \
      -sS -o /dev/null -w "HTTP %{http_code}\n" \
      http://127.0.0.1:8080/

Stop the ECONNREFUSED from coming back

Habits that keep ports, addresses and startup order predictable, so clients find the listener they expect.

  1. Set server.strictPort: true in vite.config, so Vite exits on a taken port and you notice.

  2. Read the port from one environment variable in both the server and every client config.

  3. In Docker Compose, give databases a healthcheck and set depends_on to condition: service_healthy.

  4. Wherever a proxy variable is set, add NO_PROXY=localhost,127.0.0.1 so local calls skip the proxy.

  5. Give long-running containers a restart policy such as on-failure, so a crash does not leave the port closed.

Paste the format your tool readsGeonode's docs give five proxy endpoint formats, from hostname:port to a full http:// URL.
Try residential proxies

Related errors

Learn more

FAQ

The connection attempt was turned down: the machine at that IP is reachable, but nothing is bound to its port. The error text ends with the exact IP and port that refused.

Vite's dev server passed a request matching server.proxy to its target, and nothing was listening there. Vite logs the path and returns 502 to the browser; start the backend or correct the target URL.

From Node.js 20 and 18.18 on, Node tries each IPv6 and IPv4 address a name resolves to, in turn. When every attempt is refused, it reports one AggregateError with code ECONNREFUSED and lists each refusal in err.errors.

Since Node.js 17, localhost can resolve to ::1 first, as it does on macOS. Node.js 17, 19 and 18 before 18.18 then try only that address by default, so they miss a server bound to IPv4 alone.

A refusal shows up at once (curl reports 0 ms) because the host replied with a reset. connect ETIMEDOUT means no reply came before the system gave up, usually a firewall dropping packets or a wrong address.

It is the same refusal on Linux, where ECONNREFUSED is errno 111; macOS shows [Errno 61] and Windows [WinError 10061]. Python raises ConnectionRefusedError, and requests wraps it in a ConnectionError.

Proxy URLs with no login inside

IP whitelisting lets HTTP_PROXY name only a Geonode gateway's host and port.