JavaScript Curriculum
When Things Go Wrong
mediumNexus fetches user data from an API. Sometimes the network fails. Sometimes the response is malformed JSON. Sometimes the user id doesn't exist. Right now the app crashes silently and users see a blank screen. A senior engineer is telling you: every operation that can fail, must have a plan for when it does.
Errors are inevitable — the question is how you handle them
Production code operates in a hostile environment. APIs go down. Users send unexpected input. Third-party libraries throw exceptions. Files don't exist. Network requests time out.
Unhandled errors crash your program and leave users with no information. Handled errors let your program recover, give the user useful feedback, and leave a precise diagnostic trail for you to debug later.
JavaScript provides a first-class system for this: try, catch, finally, and throw.
try / catch / finally
The structure is deliberately simple. You mark the code that might fail with try. You tell JavaScript what to do when it does fail with catch. You do any cleanup that must happen regardless with finally.
Select a scenario below and watch exactly which lines execute and which are bypassed:
execution output
hit run to trace the execution path…
The Error object
When an error is thrown, it comes with a standard structure. The catch parameter gives you direct access to it:
Every built-in error inherits from Error. You can also create your own:
Native error types
JavaScript has six built-in error types. Knowing which one you're dealing with tells you exactly what went wrong:
TypeError
Wrong type of thing for this operation
common triggers
Calling a non-function, accessing properties on null/undefined, wrong method for the type
example code
null.name // TypeError: Cannot read properties of null const n = 42 n.toUpperCase() // TypeError: n.toUpperCase is not a function
how to catch
try { ... } catch (err) {
if (err instanceof TypeError) {
// handle it
}
}💡 in practice
The most common runtime error. Usually means you assumed something was an object or function when it was actually null, undefined, or a primitive.
The two you'll encounter constantly are TypeError (wrong type — usually null/undefined access) and ReferenceError (variable doesn't exist — usually a typo or scope bug). The others are more situational.
Throwing your own errors
throw terminates the current execution and sends an error up the call stack until something catches it. You can throw anything, but always throw an Error object so the caller gets a stack trace:
You can create custom error classes for domain-specific problems — highly useful in larger codebases:
return null vs throw — a crucial design decision
When a function can't complete its job, it faces a fork: return a null/undefined sentinel value and leave it to the caller to notice, or throw an error that forces the caller to deal with it.
Step through both approaches below:
getUser function
calling code
Step through to trace what happens when getUser receives a null id.
The finally block — guaranteed cleanup
finally runs regardless of whether try succeeded or catch handled an error. It's essential for cleanup that must happen no matter what — closing database connections, releasing locks, resetting UI state:
Without finally, a thrown error in the try block would leave the spinner showing forever.
Defensive JSON parsing — your challenge
JSON.parse throws a SyntaxError on invalid input. That makes it one of the most common places you'll write try/catch in real JavaScript code.
Your implementation needs to handle three cases cleanly — valid data passes through, invalid JSON is caught, and missing fields are validated and thrown before they cause problems downstream.
Challenge
Write a function called parseUserData(jsonString) that uses try/catch to safely parse a JSON string into a user object. If parsing succeeds, validate that the result has a name property — if it doesn't, throw a new Error with the message \"Missing required field: name\". If anything fails, catch the error, log it with console.error, and return null. Test it with valid JSON, invalid JSON, and JSON missing the name field.
When Things Go Wrong
mediumNexus fetches user data from an API. Sometimes the network fails. Sometimes the response is malformed JSON. Sometimes the user id doesn't exist. Right now the app crashes silently and users see a blank screen. A senior engineer is telling you: every operation that can fail, must have a plan for when it does.
Errors are inevitable — the question is how you handle them
Production code operates in a hostile environment. APIs go down. Users send unexpected input. Third-party libraries throw exceptions. Files don't exist. Network requests time out.
Unhandled errors crash your program and leave users with no information. Handled errors let your program recover, give the user useful feedback, and leave a precise diagnostic trail for you to debug later.
JavaScript provides a first-class system for this: try, catch, finally, and throw.
try / catch / finally
The structure is deliberately simple. You mark the code that might fail with try. You tell JavaScript what to do when it does fail with catch. You do any cleanup that must happen regardless with finally.
Select a scenario below and watch exactly which lines execute and which are bypassed:
execution output
hit run to trace the execution path…
The Error object
When an error is thrown, it comes with a standard structure. The catch parameter gives you direct access to it:
Every built-in error inherits from Error. You can also create your own:
Native error types
JavaScript has six built-in error types. Knowing which one you're dealing with tells you exactly what went wrong:
TypeError
Wrong type of thing for this operation
common triggers
Calling a non-function, accessing properties on null/undefined, wrong method for the type
example code
null.name // TypeError: Cannot read properties of null const n = 42 n.toUpperCase() // TypeError: n.toUpperCase is not a function
how to catch
try { ... } catch (err) {
if (err instanceof TypeError) {
// handle it
}
}💡 in practice
The most common runtime error. Usually means you assumed something was an object or function when it was actually null, undefined, or a primitive.
The two you'll encounter constantly are TypeError (wrong type — usually null/undefined access) and ReferenceError (variable doesn't exist — usually a typo or scope bug). The others are more situational.
Throwing your own errors
throw terminates the current execution and sends an error up the call stack until something catches it. You can throw anything, but always throw an Error object so the caller gets a stack trace:
You can create custom error classes for domain-specific problems — highly useful in larger codebases:
return null vs throw — a crucial design decision
When a function can't complete its job, it faces a fork: return a null/undefined sentinel value and leave it to the caller to notice, or throw an error that forces the caller to deal with it.
Step through both approaches below:
getUser function
calling code
Step through to trace what happens when getUser receives a null id.
The finally block — guaranteed cleanup
finally runs regardless of whether try succeeded or catch handled an error. It's essential for cleanup that must happen no matter what — closing database connections, releasing locks, resetting UI state:
Without finally, a thrown error in the try block would leave the spinner showing forever.
Defensive JSON parsing — your challenge
JSON.parse throws a SyntaxError on invalid input. That makes it one of the most common places you'll write try/catch in real JavaScript code.
Your implementation needs to handle three cases cleanly — valid data passes through, invalid JSON is caught, and missing fields are validated and thrown before they cause problems downstream.
Challenge
Write a function called parseUserData(jsonString) that uses try/catch to safely parse a JSON string into a user object. If parsing succeeds, validate that the result has a name property — if it doesn't, throw a new Error with the message \"Missing required field: name\". If anything fails, catch the error, log it with console.error, and return null. Test it with valid JSON, invalid JSON, and JSON missing the name field.