Skip to content

Revision 1 — the current text. The evidence on this page is this revision’s own — it has not been carried forward from, or to, any other revision.

Diagnosing Node.js ECONNREFUSED

Confirms nothing is actually listening at the target address, then splits between a host/port misconfiguration (wrong address for where the dependency actually lives) and a startup-order race (the app connects before its dependency is ready). It does not cover connection timeouts (ETIMEDOUT), which point at network reachability rather than an actively refused connection, and it isn't specific to any one dependency — the same triage applies whether the target is a database, cache, or another service.

Unverifiedno reproductions yetWhy this confidence?
Revision 1published by DevYou curation

Symptoms

The diagnostic path

8 steps, exactly as this revision published them.

  1. Step 1 · StartNode process throws ECONNREFUSED

    ECONNREFUSED means the TCP handshake reached the target host and was actively rejected (an RST) — nothing is listening on that exact port there right now. This narrows the cause to three things: nothing's listening yet, the app is connecting to the wrong host/port, or the thing that should be listening crashed.

    What happens next

    • passed step 2, Is anything currently listening at that exact host and port?
  2. Step 2 · TestIs anything currently listening at that exact host and port?

    Check on the target host itself (locally, in the container, or via the orchestrator) whether the address the error names is actually bound by anything right now.

    Read-onlysh
    ss -ltnp | grep <port>

    Expected result

    (no output)

    What happens next

    • passed step 3, Does the app's configured address actually match where the dependency lives?
    • failed step 4, Something is listening there right now
    • unknown step 3, Does the app's configured address actually match where the dependency lives?
  3. Step 3 · TestDoes the app's configured address actually match where the dependency lives?

    Print the resolved connection config the process is actually using and compare it against where the dependency really runs — a classic mismatch is a config pointing at localhost/127.0.0.1 when the dependency is actually a separate container or pod reachable only by its own service name.

    Read-onlysh
    node -e "console.log(process.env.DATABASE_URL)"

    Expected result

    postgres://app:***@127.0.0.1:5432/app

    What happens next

    • passed step 5, Root cause: wrong host/port for where the dependency actually runs
    • failed step 6, Did the dependency actually finish starting, or has it crashed?
    • unknown step 6, Did the dependency actually finish starting, or has it crashed?
  4. Step 4 · EndSomething is listening there right now

    A plain ECONNREFUSED shouldn't be reproducible any more if something is actively listening at that address. This was probably transient — the service was mid-restart at the exact moment of connection — or the error being chased is stale. Re-run the failing call and see if it recurs.

  5. Step 5 · Root causeRoot cause: wrong host/port for where the dependency actually runs

    The configured address doesn't match where the dependency lives — for example use the Docker Compose service name instead of localhost, or the Kubernetes Service DNS name (<service>.<namespace>.svc.cluster.local) instead of 127.0.0.1. The exact fix is app/environment specific from here.

  6. Step 6 · TestDid the dependency actually finish starting, or has it crashed?

    The configured address genuinely matches where the dependency should be — check the dependency's own logs/status rather than the connecting app's.

    Read-onlysh
    kubectl logs <dependency-pod> -n <namespace> --previous

    Expected result

    (dependency's own startup or crash log)

    What happens next

    • passed step 7, Root cause: startup-order race
    • failed step 8, Dependency believes it's listening but still refuses this app
    • unknown step 8, Dependency believes it's listening but still refuses this app
  7. Step 7 · Root causeRoot cause: startup-order race

    The dependency isn't running yet, is still starting, or crashed — the Node app tried to connect before it was actually accepting connections. The robust fix is retrying the connection with backoff on the Node side; the alternative is an explicit startup dependency, such as Compose's depends_on with a healthcheck condition, or a Kubernetes init container that waits for the dependency to be ready.

  8. Step 8 · EndDependency believes it's listening but still refuses this app

    The dependency's own logs say it started and is listening, yet this app still gets refused — check that it's actually listening on the interface the app connects through (a service bound only to 127.0.0.1 inside its own container refuses connections from other containers/pods, which need it bound to 0.0.0.0), and that both sides are on the same Docker network / Kubernetes namespace with an actual route between them.

Sources

Why this confidence?

What would strengthen it: 6 more independent reproductions. Reproductions from 3 more distinct environments.

This counts only what was recorded against revision 1 itself. Nothing reported against another revision is included here — see the revision history for why.