Understanding the Error Handling API in Svelte Components
Quick answer
Svelte has no single error-handling API and no <svelte:error> element. For async work, use the {#await} block's {:catch error} branch. In Svelte 5, wrap a subtree in <svelte:boundary> with a failed snippet to contain render errors. In SvelteKit, add a +error.svelte page for route-level errors and the handleError hook for logging.
Svelte does not have one unified "Error Handling API". It has three distinct mechanisms, depending on where the error comes from.
There is also no <svelte:error> element — that is not part of Svelte, and
using it is a compile error. The real special elements are <svelte:window>,
<svelte:document>, <svelte:body>, <svelte:head>, <svelte:options>,
<svelte:fragment>, <svelte:component>, <svelte:element>,
<svelte:self>, and — in Svelte 5 — <svelte:boundary>.
1. Async errors: the catch branch of an await block
For anything promise-based, the {#await} block handles all three states:
<script>
async function fetchData() {
const res = await fetch('https://api.example.com/data');
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
return res.json();
}
let promise = fetchData();
</script>
{#await promise}
<p>Loading…</p>
{:then data}
<ul>
{#each data as item}
<li>{item}</li>
{/each}
</ul>
{:catch error}
<p class="error">Could not load data: {error.message}</p>
{/await}Svelte switches to the catch branch automatically when the promise rejects — no manual error state needed.
2. Render errors: <svelte:boundary> (Svelte 5)
Svelte 5 adds a real error boundary. Errors thrown while rendering the subtree,
or inside its effects, are caught and replaced with the failed snippet:
<svelte:boundary>
<RiskyComponent />
{#snippet failed(error, reset)}
<p>Something went wrong: {error.message}</p>
<button onclick={reset}>Try again</button>
{/snippet}
</svelte:boundary>It does not catch errors in event handlers or async callbacks — those need
their own try/catch.
3. Route errors: SvelteKit
For a SvelteKit app, route-level failures are handled by the framework.
+error.svelte renders when a load function or the page itself errors:
<script>
import { page } from '$app/stores';
</script>
<h1>{$page.status}</h1>
<p>{$page.error.message}</p>Throw a controlled error from load:
import { error } from '@sveltejs/kit';
export function load({ params }) {
if (!params.id) error(400, 'Missing id');
}And report unexpected ones centrally:
// src/hooks.server.js
export function handleError({ error, event }) {
console.error(error); // send to your monitoring service
return { message: 'Internal error' };
}In Svelte 3 and 4
There is no render-level boundary. Wrap risky work in try/catch yourself and
render fallback state:
<script>
let error = null;
let data = null;
async function load() {
try {
data = await fetchData();
error = null;
} catch (e) {
error = e;
}
}
</script>
{#if error}
<p class="error">{error.message}</p>
{:else if data}
<!-- render data -->
{/if}Which mechanism to reach for
| Error source | Use |
|---|---|
| Rejected promise in markup | await block, catch branch |
| Error thrown while rendering a subtree | <svelte:boundary> (Svelte 5) |
| Event handler / async callback | try/catch + component state |
SvelteKit route or load | +error.svelte, error(), handleError |
Key takeaways
- •There is no <svelte:error> element in Svelte — the special elements are window, document, body, head, options, fragment, component, element, self, and boundary.
- •{#await promise} ... {:catch error} is the idiomatic way to handle a failed async operation in markup.
- •Svelte 5 adds <svelte:boundary>, which catches render and effect errors in its subtree and shows a failed snippet.
- •In Svelte 3 and 4 there is no render-level boundary — catch errors in your own code with try/catch and render fallback state yourself.
- •SvelteKit handles route errors with +error.svelte, and the handleError hook is where you report them to a logging service.
- •A try/catch inside a script block only catches errors in that function, not errors thrown while rendering child components.
Frequently asked questions
Is there a <svelte:error> element in Svelte?
No. Svelte's special elements are svelte:window, svelte:document, svelte:body, svelte:head, svelte:options, svelte:fragment, svelte:component, svelte:element, svelte:self, and svelte:boundary in Svelte 5. Writing <svelte:error> is a compile error.
How do I handle an error from an async operation in Svelte?
Use the await block's catch branch: {#await promise} loading {:then value} success {:catch error} <p>{error.message}</p> {/await}. Svelte renders the catch branch automatically when the promise rejects, so you do not need manual state for the error case.
What is <svelte:boundary> and when should I use it?
Introduced in Svelte 5, it is an error boundary: wrap part of your component tree in it and provide a failed snippet, and errors thrown while rendering or in effects inside that subtree are caught and the fallback shown instead of tearing down the app. It does not catch errors in event handlers or async callbacks.
How do I handle errors in SvelteKit?
Add a +error.svelte file beside a route to render route-level load and rendering errors, throw the error helper from load functions to control status and message, and use the handleError hook in hooks.server.js to log unexpected errors to your monitoring service.
Why doesn't my try/catch catch a component render error?
A try/catch only wraps the synchronous code inside that function. Errors thrown while Svelte renders a child component or runs an effect happen outside that call stack. Use <svelte:boundary> in Svelte 5, or restructure so the failure surfaces as state your markup can branch on.