Search code examples
javascripterror-handlingpromisetry-catchuncaught-exception

Javascript uncaugh error in promise even with a catch


With Javascript, I am trying to make a call to an external API when a form is submited. I am using promises in order to set follow up actions once the call is done and to catch eventual errors.

This is where my problem is, even if I think I am catching my errors correctly, the console throws an

Uncaught (in promise) error : [The error I throw]

I do not understand why.

Here is a minimal version of my code which would reproduce the error when the refreshToken is expired :

try {
        functionGeneratingTheError();
    } catch (error) {
        doSomethingElse();
    }
function functionGeneratingTheError() {
    
    var getTokenCallPayload = {
        "client_id" : clientId,
        "client_secret" : clientSecret,
        "refresh_token" : refreshToken,
        "grant_type" : "refresh_token"
    };
    var getTokenCallOptions = {
        "method" : "POST",
        "body" : JSON.stringify(getTokenCallPayload),
        "muteHttpExceptions" : false
    };
    fetch(tokenURL, getTokenCallOptions)
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error("Error");
        }
    })
    .then(data => {
        doSomething();
    })  
    .then(response=> {
        doSomethingAgain();
    }) 
    .catch(error => {
        throw error;
    });
}

If I understand correctly, when the fetch is a bad request, it should throw the error "Error" which should then be caught in the first catch and run the doSomethingElse() function. However, instead of doing that, I get this error in the browser console "Uncaught (in promise) Error: Error"

What am I doing wrong ?

I have tried including the fetch in a try{}catch(){} but it doesn't change anything.

I also tried not throwing the error and directly call my doSomethingElse() function, but then the following .then fails because data is undefined.


Solution

  • Change your functionGeneratingTheError function to return the chained promise like below:

    function functionGeneratingTheError() {
        
        var getTokenCallPayload = {
            "client_id" : clientId,
            "client_secret" : clientSecret,
            "refresh_token" : refreshToken,
            "grant_type" : "refresh_token"
        };
        var getTokenCallOptions = {
            "method" : "POST",
            "body" : JSON.stringify(getTokenCallPayload),
            "muteHttpExceptions" : false
        };
    
        return
        fetch(tokenURL, getTokenCallOptions)
        .then(response => {
            if (response.ok) {
                return response.json();
            } else {
                throw new Error("Error");
            }
        })
        .then(data => {
            doSomething();
        })  
        .then(response=> {
            doSomethingAgain();
        }) 
        .catch(error => {
            throw error;
        });
    }
    
    

    And then await it in your calling code by wrapping the calling code inside an async self invoking function like so:

    (async function() {
    try {
            await functionGeneratingTheError();
        } catch (error) {
            doSomethingElse();
        }
    })();
    

    You can read more about async/await here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function