Oops, I did it again: A guide to debugging common JavaScript errors

Ali Spittel - Mar 25 '19 - - Dev Community

Writing JavaScript code can sometimes make us feel like running, hiding, or just being scared. But, with some debugging tips we can get in the zone and then dance until the world ends!

TypeError: Cannot read property "lucky" of undefined

let girl = {
    name: "Lucky",
    location: "Hollywood",
    profession: "star",
    thingsMissingInHerLife: true,
    lovely: true,
    cry: function() {
        return "cry, cry, cries in her lonely heart"
    }
}

console.log(girl.named.lucky)
Enter fullscreen mode Exit fullscreen mode

This code throws the error "Uncaught TypeError: Cannot read property 'lucky' of undefined". In our girl object, we don't have the property named, though we do have name. Since girl.named is undefined, we can't access a property on something that doesn't exist. So, as is true for the girl named Lucky, something's missing from our life (or object). We would want to change girl.named.lucky to girl.name, and we'd get "Lucky" in return!

A property is a value in a JavaScript object. You can read more about objects here.

Steps to debug TypeErrors

TypeErrors are caused by trying to perform an operation on something that doesn't have a data type that matches up with said operation. So, trying to run .bold() on a number, retrieve an attribute on undefined, or trying to run something like a function that's not a function (for example girl() would throw an error -- girl is an object, not a function). On the last two, we'd get "Uncaught TypeError: yourVariable.bold is not a function" and "girl is not a function".

In order to debug these errors, you need to check your variables -- what are they? What is girl? What is girl.named? Is it what it's supposed to be? You can check this by looking at your code, console.log-ing your variables, using a debugger statement, or just typing the variable into the console and seeing what it is! Make sure you can perform the action on the data type of the variable. If not, cast the data type of the variable, add a conditional or try/catch to only run that action sometimes, or run the action on something else!

Stack overflow

According to the songwriters for "Baby One More Time", the "hit" in "Hit me baby, one more time" refers to a call, so Britney wants her ex-partner to call her one more time. Which will probably lead to more and more calls in the future. This mirrors recursion -- which, if the call stack size is overflowed, will cause errors.

These change by browser, but can look like:

Error: Out of stack space (Edge)
InternalError: too much recursion (Firefox)
RangeError: Maximum call stack size exceeded (Chrome)
Enter fullscreen mode Exit fullscreen mode

This can be caused by not having a recursion base case, or having a base case that never fires.

function oneMoreTime(stillBelieve=true, loneliness=0) {
    if (!stillBelieve && loneliness < 0) return
    loneliness++
    return oneMoreTime(stillBelieve, loneliness)
}
Enter fullscreen mode Exit fullscreen mode

In the above function, stillBelieve never becomes false and loneliness keeps increasing, so we keep recursively calling oneMoreTime without ever exiting the function.

If we instead make it so that Britney relies on her friends, instead decreasing her loneliness, and she stops believing in the relationship, she'll stop wanting her ex-partner to call.

function oneMoreTime(stillBelieve=true, loneliness=0) {
    if (!stillBelieve && loneliness < 0) return
    loneliness--
    stillBelieve = false
    return oneMoreTime(stillBelieve, loneliness)
}
Enter fullscreen mode Exit fullscreen mode

There's a similar issue with infinite loops, though instead of getting an error message, our page usually just freezes. This happens when we have an un-terminated while loop.

let worldEnded = false

while (worldEnded !== true) {
  console.log("Keep on dancin' till the world ends")
}
Enter fullscreen mode Exit fullscreen mode

We can fix this in a similar way!

let worldEnded = false

while (worldEnded !== true) {
  console.log("Keep on dancin' till the world ends")
  worldEnded = true
}
Enter fullscreen mode Exit fullscreen mode

Debugging infinite loops and unterminated recursion

First, if you're in an infinite loop, quit the tab if you're in Chrome or Edge, and quit the browser window in FireFox. Then, do a check on your code: is there something that's glaringly creating the infinite loop/recursion? If not, I would add a debugger statement to the loop or function and make sure the variables are what they should be in the first few iterations -- you'll probably notice a pattern of something being off. In the above example, I would put a debugger in the first line of the function or loop. Then, I'd go to the debugging tab in Chrome, look at the variables in Scope Then, I'd click the "next" button to see what they are after an iteration or two. Usually that will get us to the solution!

This is a great guide to debugging with Chrome's DevTools, and here's one for FireFox.

Uncaught SyntaxError: Unexpected identifier

Potentially the most common category of errors in JavaScript is SyntaxError's -- these mean that we aren't following the syntax rules of JavaScript. To follow the sentiment of Britney in "Everytime", JavaScript is saying "I guess I need you baby" to our missing parenthesis, brackets, and quotation marks.

I would make sure you have a good text editor theme or extensions installed if you struggle with these types of errors -- Bracket Pair Colorizer helps color code braces and brackets, and Prettier or another linter can help catch these errors fast. Also, make sure to properly indent your code and keep codeblocks short and as un-nested as possible. This will make debugging any issues easier!


Now, with your new debugging skills, you can feel a little stronger than yesterday at JavaScript. If you are thinking Gimme More pop culture code references, here's thank u next: an introduction to linked lists.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .