Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: fetch failed due to ECONNREFUSED cannot be caught and handled #2953

Closed
Radiergummi opened this issue Mar 13, 2024 · 2 comments
Closed
Labels
bug Something isn't working

Comments

@Radiergummi
Copy link

Bug Description

I'm working with an API that is a bit unstable; in some cases, the server might go down entirely, and I need to account for that, log an error, and retry later. Alas, if the server is down Node encounters a refused connection, which in turn triggers a fetch failed error in Undici, and that - for some reason - kills the entire process.

Reproducible By

Take a look at this example (the Open Notify API used here isn't available via HTTPS, triggering the same error):

async function loadPosition() {
    const response = await fetch('https://api.open-notify.org/iss-now.json');
    const data = await response.json();

    if (!response.ok || !data.iss_position || data.message !== 'success') {
        throw new Error('Invalid response');
    }

    const {latitude, longitude} = data.iss_position || {};

    return {latitude, longitude};
}

setTimeout(async () => {
    try {
        const {latitude, longitude} = await loadPosition();
        console.log(`The ISS is at ${latitude}/${longitude}!`)
    } catch (error) {
        console.error('Could not fetch ISS position data');
    } finally {
        setTimeout(loadPosition, 5000);
    }
}, 5000)

Expected Behavior

If a connection error occurs, I'd expect it to be caught in the catch block, reported on the console, and be done with; the newly scheduled timeout in the finally block should be run after just fine.

Logs & Screenshots

Instead, this causes the process to exit immediately:

Could not fetch ISS position data
 node:internal/deps/undici/undici:13737
       Error.captureStackTrace(err, this);
             ^
 
 TypeError: fetch failed
     at node:internal/deps/undici/undici:13737:13
     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
     at Timeout.loadPosition (/index.ts:53:22) {
   [cause]: Error: connect ECONNREFUSED 138.68.39.196:443
       at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1605:16) {
     errno: -111,
     code: 'ECONNREFUSED',
     syscall: 'connect',
     address: '138.68.39.196',
     port: 443
   }
 }
 
 Node.js v21.7.1

[Process exited with code 0]

Environment

MacOS 14.3.1
NodeJS 21.7.1

@Radiergummi Radiergummi added the bug Something isn't working label Mar 13, 2024
@metcoder95
Copy link
Member

metcoder95 commented Mar 13, 2024

👋
The issue is rooted to the way your code is scheduling the retry within the timeout for retrying once more.
The first setTimeout has the correct statements for handling a situation of a failure in case of an error, but on the second timeout called within the finally scope, it just calls the loadPosition once more without any error handling; meaning that if it fails, it will be treated as an unhandled rejection leading to the process termnation.

A possible alternative can be:

async function loadPosition () {
  const response = await fetch('https://api.open-notify.org/iss-now.json')
  const data = await response.json()

  if (!response.ok || !data.iss_position || data.message !== 'success') {
    throw new Error('Invalid response')
  }

  const { latitude, longitude } = data.iss_position || {}

  return { latitude, longitude }
}

const callback = async () => {
  try {
    const { latitude, longitude } = await loadPosition()
    console.log(`The ISS is at ${latitude}/${longitude}!`)
  } catch (error) {
    console.error('Could not fetch ISS position data')
  } finally {
    setTimeout(callback, 5000)
  }
}

setTimeout(callback, 5000)

It produces:

Could not fetch ISS position data
Could not fetch ISS position data
Could not fetch ISS position data

@mcollina mcollina closed this as not planned Won't fix, can't repro, duplicate, stale Mar 13, 2024
@Radiergummi
Copy link
Author

Ohh, this is embarrassing. Of course. Thanks a bunch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants