ドキュメント一覧
/

Next.js の redirect() と notFound() は例外を throw する

Next.js の redirect() と notFound() は例外を throw する

Next.js App Router の redirect()、notFound()、permanentRedirect() が例外を throw する仕組みと、try/catch ブロックでの正しい扱い方を解説します。

最終更新: 2026年2月1日

この記事は Next.js 16.1.6 時点での情報を元に書かれています。

この記事で学べること

  • redirect()notFound()permanentRedirect() の基本的な使い方
  • これらの関数が例外を throw する理由
  • try/catch ブロックでの正しい扱い方
  • unstable_rethrow を使った解決方法

前提知識

  • Next.js App Router の基本的な使い方
  • JavaScript の try/catch 構文の理解

redirect(), notFound(), permanentRedirect() とは

Next.js App Router では、ページのリダイレクトや 404 エラーの表示を行うための関数が用意されています。これらはすべて next/navigation からインポートして使用します。

各関数の役割

関数役割
redirect()指定した URL に一時的にリダイレクト
permanentRedirect()指定した URL に恒久的にリダイレクト
notFound()404 Not Found ページを表示

基本的な使い方

import { redirect, notFound, permanentRedirect } from "next/navigation"; // 一時的なリダイレクト export default async function Page() { const user = await getUser(); // ユーザーがログインしていなければログインページへリダイレクト if (!user) { redirect("/login"); } return <div>ようこそ、{user.name} さん</div>; }
import { notFound } from "next/navigation"; // 404 ページを表示 export default async function PostPage({ params }: { params: { id: string } }) { const post = await getPost(params.id); // 記事が見つからなければ 404 を表示 if (!post) { notFound(); } return <article>{post.content}</article>; }
import { permanentRedirect } from "next/navigation"; // 恒久的なリダイレクト(URL が永久に変更された場合) export default function OldPage() { permanentRedirect("/new-page"); }

これらの関数は例外を throw する

redirect()notFound()permanentRedirect() は、通常の関数とは異なり、内部的に例外(Error)を throw します。これは Next.js の設計上の重要な特徴です。

関数エラーメッセージ
redirect()NEXT_REDIRECT
permanentRedirect()NEXT_REDIRECT
notFound()NEXT_HTTP_ERROR_FALLBACK;404
import { notFound, permanentRedirect, redirect } from "next/navigation"; try { redirect("/"); } catch (error) { console.error(error); // => Error: NEXT_REDIRECT } try { permanentRedirect("/"); } catch (error) { console.error(error); // => Error: NEXT_REDIRECT } try { notFound(); } catch (error) { console.error(error); // => Error: NEXT_HTTP_ERROR_FALLBACK;404 }

なぜ例外を throw するのか

これらの関数が例外を throw する理由は、React のレンダリングを即座に中断し、Next.js のフレームワークに制御を渡すためです。

通常の関数のように値を返すだけでは、その後のコードが実行されてしまいます。例外を throw することで、以下のことが可能になります。

  1. コンポーネントのレンダリングを即座に停止する
  2. Next.js がリダイレクトや 404 の処理を引き継ぐ
  3. 適切な HTTP レスポンスをクライアントに返す

try/catch ブロックでの問題点

redirect()notFound() が例外を throw するという仕組みを理解すると、try/catch ブロック内で使用したときに問題が起きる理由がわかります。

問題が起きるコード例

以下のコードは、一見正しく見えますが、意図した通りに動作しません。

import { redirect } from "next/navigation"; export default async function Page() { try { const user = await getUser(); if (!user) { // このリダイレクトは実行されない! redirect("/login"); } return <div>ようこそ、{user.name} さん</div>; } catch (error) { // redirect() が throw したエラーがここでキャッチされてしまう console.error("エラーが発生しました:", error); return <div>エラーが発生しました</div>; } }

なぜ問題が起きるのか

  1. redirect("/login") が呼び出される
  2. 内部的に NEXT_REDIRECT エラーが throw される
  3. catch ブロックがこのエラーをキャッチしてしまう
  4. Next.js にエラーが到達せず、リダイレクトが実行されない
  5. 代わりに「エラーが発生しました」が表示される

Next.js の公式ドキュメントでは、この点について明確に警告しています。

redirect throws an error so it should be called outside the try block when using try/catch statements.

Functions: redirect | Next.js

解決方法 1: try/catch の外で呼び出す(推奨)

最もシンプルで推奨される解決方法は、redirect()notFound() を try/catch ブロックの外で呼び出すことです。

import { redirect } from "next/navigation"; export default async function Page() { // エラーが発生する可能性のある処理だけを try/catch で囲む let user; try { user = await getUser(); } catch (error) { console.error("ユーザー取得に失敗しました:", error); return <div>エラーが発生しました</div>; } // redirect は try/catch の外で呼び出す if (!user) { redirect("/login"); } return <div>ようこそ、{user.name} さん</div>; }

解決方法 2: unstable_rethrow を使用する

どうしても try/catch ブロック内で redirect()notFound() を呼び出す必要がある場合は、unstable_rethrow を使用できます。

unstable_rethrow は、Next.js 内部で使用される特別なエラー(リダイレクトや 404 など)を再度 throw するための関数です。catch ブロックでこの関数を呼び出すと、Next.js のエラーだけを上位に伝播させ、それ以外のエラーは通常通り処理できます。

使用例

import { redirect, unstable_rethrow } from "next/navigation"; export default async function Page() { try { const user = await getUser(); if (!user) { redirect("/login"); } return <div>ようこそ、{user.name} さん</div>; } catch (error) { // Next.js 内部のエラーは再度 throw する unstable_rethrow(error); // それ以外のエラーはここで処理する console.error("エラーが発生しました:", error); return <div>エラーが発生しました</div>; } }

unstable_rethrowcatch ブロックの最上部で呼び出してください。これにより、Next.js のエラーが誤って処理されることを防げます。

対象となるその他の API

unstable_rethrowredirect()notFound() だけでなく、以下の API が throw するエラーも再度 throw します。

  • cookies()
  • headers()
  • searchParams
  • fetch(..., { cache: 'no-store' })
  • fetch(..., { next: { revalidate: 0 } })

これらの API は、ルートセグメントが静的であることを強制されている場合(dynamic = 'error' や Partial Prerendering が有効な場合など)にエラーを throw します。このエラーも開発者が catch するべきではないため、unstable_rethrow の対象となっています。

以下は、cookies() を使用する例です。

import { cookies } from "next/headers"; import { unstable_rethrow } from "next/navigation"; export default async function Page() { try { // cookies() は静的レンダリングが強制されている場合にエラーを throw する const cookieStore = await cookies(); const token = cookieStore.get("token"); // 何らかの処理... } catch (error) { // cookies() が throw したエラーも unstable_rethrow で再度 throw される unstable_rethrow(error); console.error("エラーが発生しました:", error); return <div>エラーが発生しました</div>; } }

If a route segment is marked to throw an error unless it's static, a Dynamic API call will also throw an error that should similarly not be caught by the developer.

Functions: unstable_rethrow | Next.js

注意点

関数名に unstable が付いていることからわかるように、この API は将来変更される可能性があります。可能であれば、解決方法 1(try/catch の外で呼び出す)を優先してください。

unstable_rethrow の設計や今後の方向性については、Next.js の GitHub Discussion で議論されています。

補足: 例外の型について

redirect()notFound() が throw するエラーは、RedirectError のような専用クラスではなく、通常の Error クラスに型アサーションを行っているだけです。

const error = new Error(REDIRECT_ERROR_CODE) as RedirectError;
const error = new Error(DIGEST) as HTTPAccessFallbackError;

そのため、instanceof による型ガードでこれらのエラーを区別することはできません。

まとめ

この記事では、Next.js App Router の redirect()notFound()permanentRedirect() が例外を throw する仕組みについて解説しました。

要点の整理

  • これらの関数は React のレンダリングを中断するために例外を throw する
  • try/catch ブロック内で使用すると、エラーがキャッチされてしまい正しく動作しない
  • 解決方法 1(推奨): try/catch の外で呼び出す
  • 解決方法 2: unstable_rethrow を使用して Next.js のエラーを再度 throw する

参考リンク