Search code examples
node.jsaxiospromiseunhandled-promise-rejection

Axios catch crashes code, marked "UnhandledPromiseRejection"


I am trying to handle an axios call failure. I wrote the function and the code:

async function createFunction (url, APIKEY, vendorType) {
  return new Promise((resolve, reject) => {
    const options = {
      method: 'post',
      maxBodyLength: Infinity,
      url: `${url}/vendors/packages`,
      headers: { 
        'x-api-key': `${APIKEY}`
      },
      timeout: 10000,
      data: {
        "contentType": vendorType,
      }
    };
    axios.request(options)
    .then(response =>{
      if (response.status && response.status == 200) {
        resolve(response);
      } else {
        reject(`createFunction Axios call failed with status ${response.status}: ${response.data}`)
      }
    }).catch(err => {
      reject(`createFunction Axios call failed: ${err}`);
    })
  });
}

KbartFunctions.createPackage(host,APIKEY,vendortype)
.then((response) => {
console.log(response);
})

I am getting an error:

[UnhandledPromiseRejection: 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(). The promise rejected with the reason "createFunction Axios call failed: AxiosError: Request failed with status code 400".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

I thought I handled the rejection correctly, but the code crashes anyway. Because the error reads "createFunction Axios call failed:" I know it's in the Catch segment and not the then segment (otherwise it would have said "createFunction Axios call failed with status").

What am I doing wrong?


Solution

  • Couple of problems in your code:

    • Missing catch method call in the calling code: KbartFunctions.createPackage(...)
    • Unnecessary use of the Promise constructor, which is an anti-pattern

    axios.request already returns a promise, so no need to create a new promise yourself using the Promise constructor. You can just return the promise returned by axios.request(...).

    Your code can be simplified as below:

    function createFunction(url, APIKEY, vendorType) {
      const options = {
        ...
      };
    
      return axios
        .request(options)
        .then(response => {
          if (response.status && response.status == 200) {
            return response;
          } else {
            throw new Error(
              `createFunction Axios call failed with status ${response.status}:${response.data}`
            );
          }
        });
    }
    
    KbartFunctions.createPackage(host, APIKEY, vendortype)
     .then(response => {
       console.log(response);
     })
     .catch(error => { /* handle the error */ });
    
    

    Couple of points to note in the rafactored code:

    • The catch method call has been removed inside the createFunction function. This is because if you just throw the error caught in the catch method callback, you can just omit the catch method call and allow the calling code to catch and handle the error.

    • You had marked createFunction as an async function but didn't use the async-await syntax. Instead you used promise chaining. So, I removed the async keyword from the function signature.

    If you want to rewrite the createFunction using the async-await syntax, it can be done as shown below:

    async function createFunction(url, APIKEY, vendorType) {
      const options = {
        ...
      };
    
      const response = await axios.request(options);
    
      if (response.status && response.status == 200) {
        return response;
      } else {
        throw new Error(
          `createFunction Axios call failed with status ${response.status}: ${response.data}`
        );
      }
    }