SvelteKitのエラーハンドリング(+error.svelteとerror())を整理した話
SvelteKitでエラーが起きたときの処理方法を整理します。+error.svelte でエラー画面を作り、error() ヘルパーでエラーを投げる方法と、コンポーネント内でのエラー処理の違いを解説します。
エラーの種類
SvelteKitのエラーは2種類あります。
予期されたエラー(Expected Error)
→ error() ヘルパーで意図的に投げるエラー
→ 例:404 Not Found、403 Forbidden
予期しないエラー(Unexpected Error)
→ バグや予期しない例外
→ 例:DBへの接続失敗、nullアクセス
① +error.svelte でエラー画面を作る
+error.svelte を置くとエラー時に表示されます。
<!-- src/routes/+error.svelte -->
<script lang="ts">
import { page } from '$app/stores';
</script>
<h1>{$page.status} エラー</h1>
<p>{$page.error?.message}</p>
<a href="/">トップに戻る</a>
$page.status でHTTPステータスコード(404・500など)、$page.error.message でエラーメッセージを取得できます。
② load関数でエラーを投げる
// src/routes/posts/[id]/+page.server.ts
import { error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params, platform }) => {
const post = await platform!.env.DB
.prepare('SELECT * FROM posts WHERE id = ?')
.bind(params.id)
.first();
if (!post) {
error(404, '記事が見つかりません'); // +error.svelte が表示される
}
return { post };
};
error(ステータスコード, メッセージ) を呼ぶと処理が止まって +error.svelte が表示されます。
③ ネストした +error.svelte
+error.svelte はルートごとに置けます。近いほうが優先されます。
src/routes/
+error.svelte ← 全体のフォールバック
posts/
+error.svelte ← /posts 配下のエラーはこちらが表示される
[id]/
+page.server.ts
<!-- src/routes/posts/+error.svelte -->
<script lang="ts">
import { page } from '$app/stores';
</script>
<h2>記事が見つかりませんでした({$page.status})</h2>
<p>{$page.error?.message}</p>
<a href="/">トップに戻る</a>
④ コンポーネント内でのエラー処理
+error.svelte が表示されるのは load 関数や actions の中で error() を呼んだときだけです。ボタン押下などのイベントハンドラは「ページが既に表示された後」に動くため、SvelteKitがエラーをキャッチできません。
+error.svelte が表示されるケース:
✅ load関数の中で error(404, '...') を呼んだとき
✅ actions の中で error() を呼んだとき
+error.svelte が表示されないケース:
❌ ボタン押下などのイベントハンドラ内
❌ コンポーネント内の fetch 処理
❌ タイマーの中
イベントハンドラなどでは try/catch で自前でエラーを捕まえて、$state に保持して画面に表示します。
<script lang="ts">
let errorMessage = $state('');
async function handleSubmit() {
try {
const res = await fetch('/api/submit', { method: 'POST' });
if (!res.ok) {
errorMessage = `送信に失敗しました(${res.status})`;
return;
}
// 成功処理
} catch (e) {
errorMessage = 'ネットワークエラーが発生しました';
}
}
</script>
{#if errorMessage}
<p style="color: red">{errorMessage}</p>
{/if}
<button onclick={handleSubmit}>送信</button>
まとめ
| 状況 | 対応方法 |
|---|---|
| load関数で404・403を返す | error(404, 'メッセージ') |
| エラー画面をカスタマイズ | +error.svelte を作成 |
| ルートごとに異なるエラー画面 | 各ディレクトリに +error.svelte を置く |
| コンポーネント内の非同期処理 | try/catch で $state にエラーを保持 |