node-fetch: ECONNREFUSED on NodeJS 18

When using node-fetch on NodeJS 18, got ECONNREFUSED

// test.mjs
import { Server } from '@hapi/hapi'
import fetch from 'node-fetch'

const start = async () => {
  const server = new Server({
    port: 3344,
  })

  server.route([
    {
      method: 'GET',
      path: '/',
      handler: async () => {
        return JSON.stringify({ value: 'hello' })
      }
    }
  ])
  await server.start()


  const response = await fetch('http://localhost:3344')
  console.log('response', await response.text())
}

start()

Steps to reproduce the behavior:

  1. Run the above in Node 18.7.0. It fails with:
FetchError: request to http://localhost:3344/ failed, reason: connect ECONNREFUSED ::1:3344
    at ClientRequest.<anonymous> (file:///D:/code/mocktomata/node_modules/node-fetch/src/index.js:108:11)
    at ClientRequest.emit (node:events:513:28)
    at Socket.socketErrorListener (node:_http_client:481:9)
    at Socket.emit (node:events:513:28)
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  type: 'system',
  errno: 'ECONNREFUSED',
  code: 'ECONNREFUSED',
  erroredSysCall: 'connect'
}

Expected behavior

The same script will work in NodeJS 16.

Video repro: https://youtu.be/PgyYPw4RCoI

Your Environment

software version
node-fetch 2.6.7, 3.2.10
node 18.7.0
@hapi/hapi 20.2.2
Operating System Windows

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 33
  • Comments: 19 (2 by maintainers)

Commits related to this issue

Most upvoted comments

I started seeing this and the only solution I found was to use the IP 127.0.0.1 instead of localhost. I’m not sure why

there was a breaking change in node v17 that changed the default IP resolving. ip6 is preferred by default. You can add dns.setDefaultResultOrder('ipv4first') at the beginning of you app and that should fix the problem (https://nodejs.org/api/dns.html#dnssetdefaultresultorderorder)

I started seeing this and the only solution I found was to use the IP 127.0.0.1 instead of localhost. I’m not sure why

This would be since localhost resolves to ::1 which is the “equivalent” of 127.0.0.1 but in IPv6 instead of IPv4. Since the server seems to be listening only on IPv4 this means that the connection will be refused when trying ::1.

I believe that this error exists when using the builtin http module as well, and probably has to do with how Node.js does dns resolving…

If you want to move forward with this I would suggest first seeing if you can reproduce the same issue using the builtin http module, and if you can, file an issue with Node.js directly. If this cannot be reproduced in the builtin http module, than it is most likely something in this module that messes this up.

Can confirm this issue on Node version v18.8.0. I am getting the very same error on different port 8080. Calling with curl works, calling from node results in ECONNREFUSED as described above.

I can also confirm that the very same code works on node v16.17.0. I can also confirm that changing localhost to 127.0.0.1 fixes the issue.

OS: NixOS, Linux. Node-fetch: 2.6.7

why was this closed? we are still having this issue when using ‘localhost’

Node.js 18+ has built-in fetch. You just need to remove this package.

I started seeing this and the only solution I found was to use the IP 127.0.0.1 instead of localhost. I’m not sure why

Changing ‘localhost’ to ‘127.0.0.1’ has fixed the problem for me.

I changed localhost to 127.0.0.1, I don’t know what is the reason but work successfully

Is there anyone having this issue in Ubuntu 20.04.6 with node version 18.19.0?

I have the issue with node v18.17.1. Neither setting ip to 127.0.0.1 or dns.setDefaultResultOrder(‘ipv4first’); fixes the problem.

I confirmed this fixed the issue

require('node:dns').setDefaultResultOrder('ipv4first');

I started seeing this and the only solution I found was to use the IP 127.0.0.1 instead of localhost. I’m not sure why

works on node 16 but above solution doesn’t work even if the IP were changed to localhost

I started seeing this and the only solution I found was to use the IP 127.0.0.1 instead of localhost. I’m not sure why

That worked for me!

I experience the same issue, I use nvm for Windows and same code works properly for 16.17.0

Calling the server using curl is working, showing it is not a problem of @hapi/hapi:

curl http://localhost:3344 -v
*   Trying 127.0.0.1:3344...
* Connected to localhost (127.0.0.1) port 3344 (#0)
> GET / HTTP/1.1
> Host: localhost:3344
> User-Agent: curl/7.83.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-type: text/html; charset=utf-8
< cache-control: no-cache
< content-length: 17
< accept-ranges: bytes
< Date: Fri, 12 Aug 2022 07:14:03 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
{"value":"hello"}* Connection #0 to host localhost left intact

Also, running the server in NodeJS 16.16.0, the curl call gives identical result, showing @hapi/hapi works identically in both environment.