JavaScript Error Handling
Table of Contents + β
In the previous lesson, we learned how to request data from a server with the Fetch API. Now letβs learn how to handle errors gracefully, so a single failure does not crash the whole program.
π‘οΈ What is Error Handling?
An error is a problem that stops your code from running normally. Without a plan, one error halts everything that comes after it. Error handling lets you catch that problem, deal with it, and keep going. The tool for this is the try...catch statement.
try { // code that might fail} catch (error) { // code that runs only if something fails}The code in try runs first. If it fails, JavaScript jumps straight to catch instead of stopping the program.
π§© try, catch, and finally
A full error-handling block has three parts. Each one has a clear job.
| Block | When it runs | Its job |
try | Always, first | Holds the code that might fail |
catch | Only if try fails | Handles the error and receives the error object |
finally | Always, last | Runs cleanup whether or not there was an error |
The finally block is optional, but it is handy for cleanup steps that must happen either way, like hiding a loading spinner.
try { console.log("Trying...");} catch (error) { console.log("Something failed:", error.message);} finally { console.log("This always runs.");}Letβs walk through what each block does here:
- The
tryblock runs first and logs"Trying...". Since nothing fails, JavaScript skips thecatchblock. - The
catchblock stays idle because there was no error; it would only run if thetrycode had failed. - The
finallyblock runs at the end no matter what, so"This always runs."is logged whether the code succeeded or failed.
π¦ A Simple Example
Some code is risky and can fail at runtime. A good example is JSON.parse, which turns a string into an object but throws an error if the string is not valid JSON.
const badData = "{ not valid json }";
try { const result = JSON.parse(badData); console.log(result);} catch (error) { console.log("Could not read the data:", error.message);}Here JSON.parse fails on the broken string. Instead of crashing, JavaScript jumps to catch, where the error object tells you what went wrong through its message property. The program then continues normally.
The error object
The value in catch (error) is an error object. Its error.message property
is a human-readable description of the problem, which is the most useful piece
of information for figuring out what failed.
π¨ Throwing Your Own Errors
You can also create an error on purpose with throw new Error("message"). This is useful when something is technically valid JavaScript but wrong for your program, like a missing value or a bad input.
function getDiscount(price) { if (price < 0) { throw new Error("Price cannot be negative"); } return price * 0.9;}
try { console.log(getDiscount(-50));} catch (error) { console.log("Error:", error.message); // Error: Price cannot be negative}When throw runs, it stops the function immediately and sends the error to the nearest catch block, just like a built-in error would.
π Error Handling with async/await
In the previous lesson we used fetch with async/await. A network request can fail for many reasons, so wrapping it in try...catch is the standard way to handle those failures. Anything that goes wrong inside try lands in catch.
async function loadUser() { try { const response = await fetch("https://api.example.com/user"); if (!response.ok) { throw new Error("Request failed with status " + response.status); } const data = await response.json(); console.log(data); } catch (error) { console.log("Could not load user:", error.message); }}
loadUser();A failed network call makes await fetch reject, which sends the error to catch. Note the extra check on response.ok: fetch does not treat a 404 or 500 as a failure on its own, so we throw our own error to handle those cases too.
fetch and error status codes
fetch only rejects on network problems, not on HTTP errors like 404 or
500. Always check response.ok and throw your own error so bad responses
reach your catch block.
π Showing a Friendly Message
Users should never see a raw crash. With try...catch, you can catch the failure and show a clear, friendly message instead.
async function showPrice() { const status = document.querySelector("#status");
try { const response = await fetch("https://api.example.com/price"); if (!response.ok) { throw new Error("Bad response"); } const data = await response.json(); status.textContent = "The price is " + data.price; } catch (error) { status.textContent = "Sorry, we could not load the price right now."; console.log("Details:", error.message); }}The user sees a calm, helpful sentence on screen, while the technical detail is logged to the console for you. The app keeps working instead of breaking.
β οΈ Common Mistakes to Avoid
| Mistake | Problem | Solution |
An empty catch block | The error is hidden, so bugs become invisible | At least log error.message so you can see it |
Wrapping too much code in one try | You cannot tell which line actually failed | Wrap only the risky lines that can fail |
| Not handling a rejected promise | An await failure crashes with an unhandled rejection | Put await calls inside try...catch |
π§ Try It Yourself!
- Wrap a
JSON.parsecall around a broken string intry...catchand logerror.message. - Write a function that uses
throw new Error(...)when its input is invalid, then call it insidetry...catch. - Add a
finallyblock that prints a message and confirm it runs whether or not there was an error. - Wrap an
await fetchcall intry...catchand show a friendly message when it fails.
π§© What Youβve Learned
- β
try...catchhandles errors gracefully without crashing the program - β
The
catchblock receives an error object, anderror.messagedescribes the problem - β
finallyalways runs, which makes it perfect for cleanup - β
throw new Error("message")creates your own errors on purpose - β
Wrapping
await fetchintry...catchis the standard way to handle failed requests
π Whatβs Next?
Now that you can handle errors safely, letβs learn how to save data in the browser. Letβs continue to Local Storage.