TypeError: Cannot destructure property of ‘(intermediate value)’ as it is undefined

If you got this error: UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property ‘your-destructured-variable-name’ of ‘(intermediate value)’ as it is undefined: let me remind you first of all that javascript is synchronous in nature; sure, you must have heard that before but it is obvious now that you didn’t really grasp the concept.

Javascript is Synchronous

Javascript is synchronous in its execution of code – meaning that if you have the following code:

function shouldGoFirst(){
    console.log("i should go first")
}
function shouldGoSecond(){
    console.log("i should go second")
}

provided you invoke these functions in the right order,

shouldGoFirst()
shouldGoSecond()

you will always get the output:

i should go first
i should go second

they code ran synchronously or javascript executed the first function call immediately and went ahead to execute the second function call immediately – the key to remember here is immediately.

Now what if there is a delay in getting the respond back from the first function: shouldGoFirst(), what will happen? What will happen is that javascript will not wait for shouldGoFirst() to finish what it is doing and return a response before it will go ahead to execute the next lines of code; it will go ahead to execute shouldGoSecond while shouldGoFirst is delaying (if it so happens that shouldGoFirst() delays to finish execution, it is an asynchronous function – not a synchronous function).

Asynchronous Javascript

So what do we do in the case of asynchronous function or a function that is delaying to finish execution. To understand, lets look at another code sample:

function shouldGoFirst(){
    setTimeOut(() => {
        console.log("i should go first")
    }, 2000)
}
function shouldGoSecond(){
    console.log("i should go second")
}

shouldGoFirst() now delays for 2 seconds before printing “i should go first” to console; so if we were to invoke both functions the way we did before,

shouldGoFirst()
shouldGoSecond()

what output do we expect to log to the console? The output will be as follows:

i should go second
i should go first

At this point you shouldn’t be surprise anymore because i already told you that javascript is synchronous in its execution of code – meaning that immediately it begins executing shouldGoFirst(), it goes ahead to execute shouldGoSecond() without waiting for shouldGoFirst() to finish what it is doing.

This can be more frustrating if we wanted some kind of output from shouldGoFirst() to use in shouldGoSecond().

function shouldGoFirst(){
  setTimeout(() => {
    return 10 * 10;
  });
}

function shouldGoSecond(result){
  console.log(result);
}

const answer = shouldGoFirst();
shouldGoSecond(answer);

The output you get from the above code is: undefined because before shouldGoFirst() could

return the value of 100 to shouldGoSecond() to print to the console, shouldGoSecond() has already gone ahead to print result – which is undefined at the time – to the console; and this is because shouldGoFirst() delayed for 2 seconds before returning its value.

To get the output in the order which we expect it to be, we must find a way to delay shouldGoSecond() from executing until shouldGoFirst() has finished executing. To achieve this, we use a concept called: callback function in javascript.

Callback to The Rescue

function shouldGoFirst(cb){
  setTimeout(() => {
    const result = 10 * 10;
    cb(result)
  });
}

function shouldGoSecond(Result){
  console.log(Result);
}

shouldGoFirst(shouldGoSecond);

So in a bid to delay the execution of shouldGoSecond() till after the execution of shouldGoFirst(), i have to make shouldGoSecond() a callback function called upon to execute only after shouldGoFirst() has returned its value (in this case 100) to the variable result. result is then passed as a parameter to shouldGoSecond() and of course printed to the console. See output below:

Note that for this to work, the callback function is placed within the part of shouldGoFirst() that is causing delay such that soon as 100 is assigned to result, result is then passed to shouldGoSecond(). Failure to placed the callback function within shouldGoFirst() will still result in an undefined error. See below:

How to fix the nodejs error – Cannot destructure property … it is undefined

Now that you understand how to deal with asynchronous functions, let us deal with our particular error: Cannot destructure property … of ‘(intermediate value)’ as it is undefined.

That you are looking for a fix for this error, i presume that you are trying to destructure either an object or array returned from an asynchronous function or promise so you can use the destructured value(s) in your own code.

Take a look at the following scenario so that you can use it to solve your own case:

I have the following code:

const Is_Account_Under_Suspension = (req, res) => {
    var suspensionres;
    //console.log(`This is the email: ${req.body.email}`)
    const query = "SELECT Login_id, Suspension_reason FROM suspended_users WHERE email = ?";
    connection.query(query, [ req.body.email ], function(err, results) {
        if(err) throw err
        if (!results){
            return {
                sus_status : "failed",
                sus_status_msg : ""
            }
        }
        const user = results[0];

        if(user.Login_id && user.Suspension_reason == "Suspended for multiple login failure"){
            return {
                sus_status : "SUSPENDED",
                sus_status_msg : "Multiple_Login_Failure"
            }
        }

        return {
            sus_status : "NOT_SUSPENDED",
            sus_status_msg : ""
        }
    });
}

const login = (req, res) => {
    const { sus_status, sus_status_msg } = Is_Account_Under_Suspension(req, res)
    if(sus_status == "SUSPENDED" && sus_status_msg == "Multiple_Login_Failure"){
        res.status(200).send("very very good stuff")

    }
}

login function is exported and fires up once you want to login and is accessible at the endpoint: http://localhost:3000/api/v1/dev/login.

Within login, Is_Account_Under_Suspension() is called and expects to check the suspended_users table to see if the user trying to login is suspended for multiple login failures. Is_Account_Under_Suspension(req, res) returns and object of sus_status and sus_status_msg.

Now the problem is that if you try to run this code the way it is, you will be faced with the error: TypeError: Cannot destructure property ‘sus_status’ of ‘Is_Account_Under_Suspension(…)’ as it is undefined because as i have stated earlier, javascript does not wait for

Is_Account_Under_Suspension() to connect to the database, fetch the data and return corresponding response before trying to destructure sus_status and sus_status_msg defined in the left side of the code where Is_Account_Under_Suspension() is called; of course it finds that sus_status and sus_status_msg is yet to be defined since nothing has been returned from Is_Account_Under_Suspension() yet.

We must find a way to delay the destructuring until Is_Account_Under_Suspension() has actually returned the object to be destructured. Hence we will use a callback function and rewrite the code as follows:

const Is_Account_Under_Suspension = (req, res, cb) => {

        var suspensionres;

        const query = "SELECT Login_id, Suspension_reason FROM suspended_users WHERE email = ?";
        connection.query(query, [ req.body.email ], function(err, results) {
            if(err) throw err
            if (!results){
                return cb({
                    sus_status : "failed",
                    sus_status_msg : ""
                })
            }
            const user = results[0];

            if(user.Login_id && user.Suspension_reason == "Suspended for multiple login failure"){
                return cb({
                    sus_status : "SUSPENDED",
                    sus_status_msg : "Multiple_Login_Failure"
                })
            }

            return cb({
                sus_status : "NOT_SUSPENDED",
                sus_status_msg : ""
            })
        });
}

const login = (req, res) => {
    const callback = (result) => {
        const { sus_status, sus_status_msg } = result
        if(sus_status == "SUSPENDED" && sus_status_msg == "Multiple_Login_Failure"){
            res.status(200).send("very very good stuff")

        }
    }
    Is_Account_Under_Suspension(req, res, callback)

}

You can also use Promise … async/await

If you don’t like to use callbacks, then make the called function a promise and then use async/await in the calling function to destructure the returned object or array.

const Is_Account_Under_Suspension = (req, res) => {
    return new promise((resolve, reject) => {
        const query = "SELECT Login_id, Suspension_reason FROM suspended_users WHERE email = ?";
        connection.query(query, [ req.body.email ], function(err, results) {
            if(err){
                //log error
                return reject({
                    sus_status : "failed",
                    sus_status_msg : ""
                })
            }
            if (results.length < 1){
                return resolve({
                    sus_status : "failed",
                    sus_status_msg : ""
                })
            }
            const user = results[0];

            if(user.Login_id && user.Suspension_reason == "Suspended for multiple login failure"){
                return resolve({
                    sus_status : "SUSPENDED",
                    sus_status_msg : "Multiple_Login_Failure"
                })
            }

            return resolve({
                sus_status : "NOT_SUSPENDED",
                sus_status_msg : ""
            })
        });
    })
}

const login = async (req, res) => {
    try{
        const { sus_status, sus_status_msg } = await Is_Account_Under_Suspension(req, res)
        if(sus_status == "SUSPENDED" && sus_status_msg == "Multiple_Login_Failure"){
            res.status(200).send("very very good stuff")
        }
    }catch(err){
        //log error here
        //console.log(err)
        return res.status(500).json({
            sus_status : "failed",
            sus_status_msg : "An error occurred during signup process. Please try again"
        })
    }
}

You see what i did there, i use a promise to wait for the part of the Is_Account_Under_Suspension that will cause a delay to finish its execution before destructuring { sus_status, sus_status_msg } within the login function; the async/await keyword used in the login function helps me wait for the promise to either resolve or reject. If it resolves, the corresponding returned object is destructurred; if it rejects, the rejected returned object is destructured instead.

To use a promise, you need to install it by using:

npm install promise

and then reference it at the top of your code with:

var promise = require('promise');

You can use the following details if you want to test out my code

TABLE STRUCTURE:

CREATE TABLE IF NOT EXISTS `suspended_users` (
  `Id` int NOT NULL AUTO_INCREMENT,
  `email` varchar(255) NOT NULL,
  `Suspension_reason` tinytext NOT NULL,
  `Date_of_suspension` datetime NOT NULL,
  `Login_id` int DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT STATEMENT

INSERT INTO suspended_users (email, Suspension_reason, Date_of_suspension, Login_id) VALUES ('your-email@some-address.com', 'Suspended for multiple login failure', now(), 1);

I assume you know how to setup a POST route in nodejs and that you know how to use a tool like postman to test out your route.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

You May Also Like