Skip to content

ES6 - Error Handling

Error handling is a critical aspect of writing robust JavaScript applications. It involves anticipating, detecting, and responding to errors that may occur during program execution.

  • Syntax Errors: Occur when code violates the grammatical rules of JavaScript. These are detected by the JavaScript engine during parsing (before execution) and prevent the script (or module) from running. Example: a missing parenthesis.
  • Runtime Errors (Exceptions): Occur during the execution of the code. These happen when the engine encounters an operation it cannot perform. Examples: trying to call a method on an undefined variable, dividing by zero (though JS returns Infinity), or referencing an undeclared variable (in strict mode).
  • Logical Errors: The code runs without throwing syntax or runtime errors, but it doesn’t produce the intended result due to flaws in the program’s logic. These are often the hardest to debug as the engine doesn’t report them as errors.

This is the primary mechanism for handling runtime errors (exceptions) in synchronous JavaScript code.

  • try block: Contains the code that might throw an exception.
  • catch (error) block: If an exception occurs within the try block, control is transferred to the catch block. The error object (or whatever name you give the parameter) contains information about the error.
  • finally block (optional): Contains code that will execute after the try and catch blocks, regardless of whether an exception was thrown or caught. It’s often used for cleanup operations (e.g., closing resources).
try {
// Code that might throw an error
} catch (error) {
// Code to handle the error
// 'error' is an Error object
} finally {
// Code that always executes
}
function divide(a, b) {
try {
if (b === 0) {
throw new Error("Division by zero is not allowed.");
}
const result = a / b;
console.log(`Result: ${result}`);
return result;
} catch (error) {
console.error(`Error Name: ${error.name}`);
console.error(`Error Message: ${error.message}`);
// console.error(`Stack Trace: ${error.stack}`); // Useful for debugging
return null; // Or handle differently
} finally {
console.log("Division attempt finished.");
}
}
divide(10, 2); // Result: 5, Division attempt finished.
divide(10, 0); // Error messages, Division attempt finished.

When a runtime error occurs, JavaScript creates and throws an Error object (or an instance of one of its subtypes). Key properties of an Error object include:

  • name: The type of error (e.g., "Error", "TypeError", "ReferenceError").
  • message: A human-readable description of the error.
  • stack (non-standard but widely supported): A string containing the call stack trace, useful for debugging.
Sr.NoError TypeDescription
1ErrorGeneric base error object.
2EvalErrorRepresents an error regarding the global eval() function. Rarely thrown in modern JavaScript; other errors are more common.
3RangeErrorIndicates a numeric variable or parameter is outside of its valid range. (e.g., new Array(-1))
4ReferenceErrorOccurs when trying to access a variable that hasn’t been declared (in strict mode) or is out of scope.
5SyntaxErrorIndicates a parsing error in the code. These usually prevent execution and are not catchable by try...catch unless eval() or similar is used.
6TypeErrorOccurs when an operation cannot be performed, typically when a value is not of the expected type (e.g., calling a method on null or undefined, or treating a non-function as a function).
7URIErrorIndicates that encodeURI(), decodeURI(), encodeURIComponent(), or decodeURIComponent() were passed invalid parameters.

You can create and throw your own exceptions using the throw statement. You can throw any expression, but it’s best practice to throw an Error object or an instance of a custom error class derived from Error.

Syntax: throw new ErrorType("Descriptive message");

function validateAge(age) {
if (typeof age !== 'number') {
throw new TypeError("Age must be a number.");
}
if (age < 0) {
throw new RangeError("Age cannot be negative.");
}
console.log("Age is valid.");
}
try {
validateAge(-5);
} catch (e) {
console.error(`${e.name}: ${e.message}`); // RangeError: Age cannot be negative.
}

For more specific error handling, you can create custom error classes by extending the built-in Error class.

class NetworkError extends Error {
constructor(message, statusCode) {
super(message); // Call the parent constructor (Error)
this.name = "NetworkError";
this.statusCode = statusCode;
}
}
try {
// Simulate a network issue
throw new NetworkError("Failed to connect to the server.", 503);
} catch (e) {
if (e instanceof NetworkError) {
console.error(`Custom Error (${e.name}): ${e.message}, Status: ${e.statusCode}`);
} else {
console.error(`Generic Error: ${e.message}`);
}
}

try...catch only works for synchronous code. For asynchronous operations like those involving Promises or setTimeout:

  • Promises: Use the .catch(errorHandler) method or the second callback in .then(successHandler, errorHandler).
  • async/await: You can use try...catch around await expressions to handle rejections from awaited promises.
  • Callbacks: Error handling typically involves an error-first callback convention (e.g., callback(error, data)).
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Failed to fetch data:", error);
// Handle or re-throw
}
}
fetchData();

window.onerror and window.onunhandledrejection

Section titled “window.onerror and window.onunhandledrejection”
  • window.onerror = function(message, source, lineno, colno, error): A global event handler for uncaught synchronous errors that occur in scripts loaded by the window. It’s a last resort for error logging or reporting.

  • window.onunhandledrejection = function(event): A global event handler for uncaught promise rejections. The event.reason property contains the rejection value.

These global handlers are useful for telemetry and global error tracking but shouldn’t replace specific try...catch blocks or Promise .catch() handlers for application logic.

For more on error handling: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling