Inexplicable node.js http throwing connect ECONNREFUSED (IPv6?)

Brian M. Hunt picture Brian M. Hunt · Mar 5, 2013 · Viewed 11.5k times · Source

I am running node.js as follows:

> http = require('http')
> http.get('http://myhost.local:8080',
    function (res) { console.log("RES" + res) }
  ).on('error', function (e) { console.log("Error:", e) })

> uri = require('url').parse("http://myhost.local:8080")
{ protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'myhost.local:8080',
  port: '8080',
  hostname: 'myhost.local',
  hash: null,
  search: null,
  query: null,
  pathname: '/',
  path: '/',
  href: 'http://myhost.local:8080/' }
> http.get(uri,
    function (res) { console.log("RES" + res) }
  ).on('error', function (e) { console.log("Error:", e) })

An error is thrown for both the implicit and explicitly parsed URI and I get the following output for both:

Error: { [Error: connect ECONNREFUSED] code: 'ECONNREFUSED', errno: 'ECONNREFUSED', syscall: 'connect' }

The host myhost.local is an alias for localhost in /etc/hosts, being:

127.0.0.1   localhost myhost.local myhost
255.255.255.255 broadcasthost
::1             localhost myhost.local myhost
fe80::1%lo0 localhost myhost.local myhost

EDIT: I tried virtually every permutation for the hosts file, including the most obvious:

127.0.0.1   localhost 
255.255.255.255 broadcasthost
::1             localhost myhost.local myhost
fe80::1%lo0 localhost

EDIT I should also mention that I have tried this on more than one Mac now.

Although it seems this is a rather common error, I have seen no useful explanations or workarounds. Here are some notable related facts:

  1. Running $ wget http://myhost.local:8080 works as expected, so it isn't a firewall problem.
  2. Running $ telnet myhost.local 8080 and then manually GET'ing the url works fine, so it's not a weird HTTP problem.
  3. I have no trouble using node.js to connect to other hosts e.g. http://www.google.com

I expect the useful system information would include:

$ node -v
v0.9.11

$ uname -a
Darwin myhost.local 12.2.1 Darwin Kernel Version 12.2.1:
Thu Oct 18 12:13:47 PDT 2012; root:xnu-2050.20.9~1/RELEASE_X86_64 x86_64

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.8.2
BuildVersion:   12C3104

$ sudo  netstat -nalt | grep LISTEN | grep 8080
tcp6       0      0  ::1.8080  *.*    LISTEN

Does anyone have any idea what is going on here, and what a fix might be?

Answer

alessioalex picture alessioalex · Mar 6, 2013

I'm going to post this here in case somebody else has the problem.

Bert Belder, Node.js mailing list:

On your system "myhost.local" resolves to three different addresses (127.0.0.1, ::1, and fe80::1). Node prefers ipv4 over ipv6 so it'll try to connect to 127.0.0.1. Nothing is listening on 127.0.0.1:8080 so the connect() syscall fails with ECONNREFUSED. Node doesn't retry with any of the other resolved IPs - it just reports the error to you. A simple solution would be to replace 'localhost' by the intended destination ip address, '::1'.

Whether this behavior is right is somewhat open for debate, but this is what causes it.

Bert