Vue.js Error Handling
Errors happen in every application. A server stops responding, a user types unexpected text, or a developer makes a typing mistake. Good error handling keeps the page usable, shows clear messages, and records the problem for developers. A broken screen with no explanation drives visitors away, while a friendly message with a retry button keeps them on the site.
Think of a safety net under a trapeze act. The performers hope never to use it, and the show continues when someone slips. Error handling is the net beneath your code.
Catch Errors in Async Code
Network calls fail often. Wrap them in try and catch, and store the error message in reactive data so the template can display it.
<script setup>
import { ref } from "vue";
const users = ref([]);
const errorMessage = ref("");
const loading = ref(false);
async function loadUsers() {
loading.value = true;
errorMessage.value = "";
try {
const res = await fetch("/api/users");
if (!res.ok) throw new Error("Server returned " + res.status);
users.value = await res.json();
} catch (err) {
errorMessage.value = "Users could not load. Please try again.";
console.error(err);
} finally {
loading.value = false;
}
}
</script>
<template>
<p v-if="loading">Loading...</p>
<p v-else-if="errorMessage">
{{ errorMessage }}
<button @click="loadUsers">Retry</button>
</p>
<ul v-else>
<li v-for="u in users" :key="u.id">{{ u.name }}</li>
</ul>
</template>The fetch function treats a 404 or 500 response as success, so the code checks res.ok and throws an error by hand.
Diagram: Three Screen States
loading = true --> "Loading..." errorMessage has text --> message + Retry button neither --> user list
Catch Errors from Child Components
The onErrorCaptured hook in a parent component receives errors thrown by any descendant. Returning false stops the error from rising further.
<script setup>
import { ref, onErrorCaptured } from "vue";
const failed = ref(false);
onErrorCaptured((err, instance, info) => {
console.error("Caught:", err, info);
failed.value = true;
return false;
});
</script>
<template>
<p v-if="failed">This section is unavailable right now.</p>
<slot v-else />
</template>Diagram: Error Boundary
ErrorBoundary (onErrorCaptured)
|
+-- Widget A works
+-- Widget B throws an error
|
v
Boundary catches it, shows a fallback message.
Widget A and the rest of the page keep working.Build a Reusable Error Boundary
Move the hook into a small component that wraps any risky area and accepts a custom fallback through a named slot.
<!-- ErrorBoundary.vue -->
<script setup>
import { ref, onErrorCaptured } from "vue";
const error = ref(null);
onErrorCaptured((err) => {
error.value = err;
return false;
});
</script>
<template>
<slot name="fallback" v-if="error" :error="error">
<p>Something went wrong.</p>
</slot>
<slot v-else />
</template>
<ErrorBoundary>
<SalesChart />
</ErrorBoundary>A Global Error Handler
The application object offers one last catch point for any error that no component handled. Developers use it to send reports to a logging service.
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
console.error("Global error:", err, info);
// send details to a logging service here
};
app.config.warnHandler = (msg) => {
console.warn("Vue warning:", msg);
};Diagram: Error Path
Error in a child component | v Parent onErrorCaptured? --yes--> handled here | no v app.config.errorHandler --> logs the error
Route Errors and Missing Pages
A catch-all route displays a friendly page for unknown addresses.
{ path: "/:pathMatch(.*)*", component: NotFound }Write Helpful Messages
- State what happened in plain words, such as "Payment could not be processed."
- Offer a next action: retry, go back, or contact support.
- Hide technical details from visitors and send them to logs instead.
- Avoid blaming the user, and never show raw server messages.
Summary
Vue error handling works in layers. try and catch protect async calls, state variables drive loading and error screens, onErrorCaptured builds boundaries around risky components, and app.config.errorHandler catches the rest for logging. Clear messages with a retry option keep visitors confident while developers receive the details they need.
