Error Handling - Issues with Unhandled promise rejection

So I'm creating a node that's using Axios to make a call to an API. I've created an async function to make that call. I'm catching any exceptions thrown by that function but it is still throwing unhandled promise rejection errors. What am I missing? Here is the basic idea:

const axios = require("axios").default;

module.exports = (RED) => {
  const sendMessage = async ({ url, message }) => {
    axios.post(url, {
      message,
    });
  };

  function MyNode(config) {
    RED.nodes.createNode(this, config);
    const node = this;
    const message = "test";
    node.on("input", async (msg) => {
      await sendMessage({
        url: node.url,
        message,
      }).catch((ex) => {
        node.error(`error while sending message: ${ex.message}`);
      });

      node.send(msg);
    });
  }

  RED.nodes.registerType("mynode", MyNode);
};

I'm catching the async call. I'm not sure why it's throwing the unhandled promise rejection when the URL is invalid. I'm sure I'm missing something stupid but I can't tell what the issue is. I've tried putting try/catch blocks around anything and everything and it still throws the exception.

Am I missing some other async call? The node.on() event handler isn't catchable so maybe it's something related to the async function I'm using there?

Any ideas?

EDIT
Here is the exact error:

(node:17) UnhandledPromiseRejectionWarning: Error: getaddrinfo ENOTFOUND whatever
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:71:26)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:17) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().

I've tried putting a try/catch block around the axios.post since the exception seems to be coming from that call when it tries to call the URL provided but the error still persists.

Catching async errors can be tricky. This post explains the issue reasonably well, I think. Error handling with Async/Await in JS | by Ian Segers | ITNEXT

Indeed. As I suspected I missed one:

  const sendMessage = async ({ url, message }) => {
    await axios.post(url, {
      message,
    });
  };

I forgot to await the axios call (or return it's promise) so it was unhandled. I knew I must have missed something small :slight_smile:

1 Like

Yes, the first few times I tried to use async/await, I got myself in some terrible messes. I think I'm finally getting there now. The new package management library in uibuilder vNext is a good example. My Drayton Wiser node is also a good example, especially compared to my original node.js library.

Next step on the hard-to-learn list is migrating my nodes over to ESM from CommonJS modules :confounded:

I'm writing a custom node and I'm planning on using ESM (right now I'm just using the CommonJS standard) but wasn't sure how much Node RED would have a fit if I tried it. I know in other (non-Node RED) projects I've done it and it was hit-or-miss with node (like having to enable experimental features in package.json).

Async await is great - when you don't do like I did and miss something :slight_smile:

EDIT - Yeah I just noticed Node RED supports Node v12 and up? Can you even get ESM to work with 12? I know you can with 14 but you have to enable experimental support.

It appears as though the Node RED loader.js uses require and it does not like it if I convert my package to a module type!

EDIT 2 - I just saw your post from a year ago about ESM modules being a mess so maybe I'll stick with ComonJS for now.

Due to how the loader uses require to load other modules how are you planning on converting your modules over to ESM? I'm poking around with it now but I'm not having any luck getting it to work (like renaming to .mjs or trying some other options like maybe using babel).

I've not tried it yet but now that node.js v12 is the minimum, I think it should be possible. It is now possible to require CommonJS modules from an ESM which I think was the missing part. There are a few gottya's though - for example, you can't simply require a JSON file in an ESM like you can with CommonJS. However, the ESM library in node.js now lets you create a reference to the require function which helps.

No, I think they are native in both versions. You can also now specify the module type using the "type" property in package.json which saves messing with extension names.

Modules: ECMAScript modules | Node.js v12.22.10 Documentation (nodejs.org)

Modules: Packages | Node.js v12.22.10 Documentation (nodejs.org)

Either things have changed or I'm getting better at node.js (or both!) because it looks like this is now feasible.

I don't see any point in using Babel, might as well stick with CommonJS, it isn't going away any time soon. I plan to use the type property in package.json. And then use module.createRequire where needed for CommonJS.

It seems doable now but still quite a bit of work. So it isn't high up on my todo list.

Some other things such as dynamic imports are also on the list to look at - that lazy loads modules that might only occasionally be needed. Potentially useful when working with something as complex as uibuilder.

Right, that's useful to know. I'll probably start by converting some of my library modules, the nodes themselves will certainly be the last to go. It would help anyway since some of my dependencies are converting to ESM and it would be useful to be able to use the latest versions.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.