Next.js APIルートにおけるNEXT_REDIRECTエラーの解決策
問題の概要
Next.js 13.4以上のバージョンでAPIルート(app/api/**/route.ts
)内でredirect
関数をtry-catchブロック内で使用した場合、以下のエラーが発生します:
Error: NEXT_REDIRECT
at getRedirectError (webpack-internal://...)
at redirect (webpack-internal://...)
at GET (webpack-internal://...)
具体的な問題の発生条件は次のコード例の通りです:
import { redirect } from 'next/navigation';
// 👎 問題のある実装
export async function GET(req: Request) {
try {
redirect('/dashboard'); // ここでエラー発生
} catch (error) {
console.log(error);
redirect('/');
}
}
一方で、try-catchブロックを使用しないシンプルなリダイレクトは正常に動作します:
// 👍 正常に動作するリダイレクト
export async function GET(req: Request) {
redirect('/dashboard');
}
根本原因
このエラーの主な原因は、Next.jsのredirect
関数が内部的にエラーをスローする仕様にあるためです:
redirect
関数はリダイレクトを実現するためにNEXT_REDIRECT
という特殊なエラーをスロー- try-catchブロック内で使用すると、このエラーが通常のエラーとしてキャッチされる
- 結果として、リダイレクト処理が中断されコンソールにエラーが表示される
Next.js公式ドキュメントでも、redirect()
はtry/catch
ブロック外で使用するよう明示されています。
解決方法
APIルートでの適切な方法(推奨)
APIルートではNextResponse.redirect
を使用するのが公式推奨の手法です:
import { NextResponse } from 'next/server';
export async function GET(req: Request) {
try {
// 認証処理など
return NextResponse.redirect(new URL('/dashboard', req.url));
} catch (error) {
console.error(error);
return NextResponse.redirect(new URL('/', req.url));
}
}
重要なポイント
NextResponse
はnext/server
からインポート- 絶対URLが必要なため
new URL()
でURLオブジェクトを生成 return
を使ってレスポンスを返す必要あり
サーバーコンポーネントでの対処法
サーバーコンポーネントでは、redirect
関数を使いつつエラー処理を行う必要がある場合、finally
ブロックを使う方法が安全です:
import { redirect } from 'next/navigation';
export default async function AuthComponent() {
let redirectPath = null;
try {
// 認証処理...
redirectPath = '/dashboard';
} catch (error) {
console.error(error);
redirectPath = '/error';
} finally {
if (redirectPath) redirect(redirectPath);
}
// コンポーネントの通常レンダリング
return <div>Loading...</div>;
}
高度な方法:リダイレクトエラーの判別
直接エラーをチェックする方法もありますが、内部APIの利用には注意が必要です:
import { redirect } from 'next/navigation';
import { isRedirectError } from 'next/dist/client/components/redirect';
export async function GET(req: Request) {
try {
redirect('/dashboard');
} catch (error) {
if (isRedirectError(error)) throw error; // リダイレクトエラーを再スロー
console.error(error);
redirect('/'); // 通常エラーの場合
}
}
注意
next/dist/
以下のモジュールは非公開APIです。バージョンアップで変更される可能性があり、プロダクションコードでの使用には注意が必要です。
避けるべきパターン
❌ 禁止1:redirectを直接try内で使う
try {
redirect('/dashboard'); // NG!
} catch (error) {
// ...
}
❌ 禁止2:redirectの前にreturnしない
try {
return redirect('/dashboard'); // これもNG!
} catch {
// ...
}
❌ 禁止3:無効なリダイレクト位置
export async function GET() {
const doRedirect = () => redirect('/'); // ネスト関数内での使用
try {
doRedirect(); // NG!
} catch {
// ...
}
}
補足情報(Next.js 15以降)
Next.js 15ではpermanentRedirect
関数が新たに導入されています:
import { permanentRedirect } from 'next/navigation';
export default function Page() {
permanentRedirect('/profile');
}
redirect
との違い
permanentRedirect
: 永続リダイレクト(ステータスコード308)redirect
: 一時リダイレクト(ステータスコード307)
詳細は公式ドキュメントを参照してください。
まとめ
Next.jsでredirect
関数をエラーハンドリングと併用する場合のポイント:
- **APIルートでは
NextResponse.redirect
**を使用 - サーバーコンポーネントでは
finally
ブロックでリダイレクト実行 - エラーハンドリングが必要ない場合、try-catchの使用は避ける
- 非公開API(
isRedirectError
)には依存しない - Next.js 15+では
permanentRedirect
も検討
これらのベストプラクティスを適用することで、NEXT_REDIRECT
エラーを発生させることなく安全なリダイレクト処理を実装できます。