Show expected errors with the error helper, customize the error page with +error.svelte, and place boundaries per section.
Why: when a record is missing, call error(status, message). It stops the load and renders the error page with the right HTTP status — cleaner than returning ad-hoc "not found" markup.
// src/routes/blog/[slug]/+page.server.ts
import { error } from '@sveltejs/kit'
import type { PageServerLoad } from './$types'
import { db } from '$lib/server/db'
export const load: PageServerLoad = async ({ params }) => {
const post = await db.getPost(params.slug)
if (!post) error(404, 'Post not found')
return { post }
}Why: add a +error.svelte and SvelteKit shows it whenever an error is thrown in that part of the app. Read the details from the page state — page.status is the code, page.error.message is the message.
<!-- src/routes/+error.svelte -->
<script lang="ts">
import { page } from '$app/state'
</script>
<h1>{page.status}</h1>
<p>{page.error?.message}</p>
<a href="/">Go home</a>Why: an +error.svelte covers its own folder and everything under it, falling back to one higher up if there isn’t a closer one. So place them where you want isolated, section-specific error UI.
src/routes/+error.svelte handles errors anywhere src/routes/blog/+error.svelte handles errors under /blog only src/routes/blog/[slug]/+page.svelte an error here -> nearest +error.svelte
Why: errors you throw with error() are "expected" — their message is shown to users. Any other thrown error is "unexpected" — SvelteKit hides its message in production (to avoid leaking details) and shows a generic one. So use error() for messages meant for users.
import { error } from '@sveltejs/kit'
// Expected: message is shown to the user
error(403, 'You do not have access to this page')
// Unexpected: a plain throw — message is hidden in production
throw new Error('Database connection string is misconfigured')