🛫
Next.js(App Router)のredirect関数に生じる謎のエラー
現象
App Router で新たに追加されたredirect 関数は、server actions やサーバーコンポーネント、route handlers で使うことができますが、実行時に、
Error: NEXT_REDIRECT at…
のようなエラーに出くわすことがあります。割と遭遇して日も経ちますが、備忘録として残しておきます。
結論
まずは結論です。以下の場合、上記のエラーが発生します。
- try...catch 構文の中で redirect 関数を使っている場合
- Promise を返却する関数内で使用する場合
解決方法は簡単で、
- これらの外で redirect 関数を使う。
- そもそも redirect 関数を使わずリダイレクト処理をする。
後者はそもそもなので、前者だけ例を示します。
example.ts
export const sendVerificationEmail = async (formData: FormData) => {
"use server";
try {
const formJson = formDataToJSON(formData);
const result = SIGN_IN_SCHEMA.safeParse(formJson);
if (!result.success) {
// zodでvalidationに引っかかった時に行われる処理
...
redirect("/sign-in");
} else {
const {
data: { email },
} = result;
// validationに通った時に行われる処理
...
redirect("/");
}
} catch (err: any) {
// catchの処理
}
};
上記のように、server actions の try...catch の中に redirect 関数を使った場合、先述のエラーが発生します。この場合は、以下のように、try...catch 構文の外であ redirect 関数を実行します。
example.ts
export const sendVerificationEmail = async (formData: FormData) => {
"use server";
let redirectTo = "" // リダイレクト先
try {
const formJson = formDataToJSON(formData);
const result = SIGN_IN_SCHEMA.safeParse(formJson);
if (!result.success) {
// zodでvalidationに引っかかった時に行われる処理
...
redirectTo = "/sign-in";
} else {
const {
data: { email },
} = result;
// validationに通った時に行われる処理
...
redirectTo = "/";
}
} catch (err: any) {
// catchの処理
}
// try...catchの外でredirect関数を実行する。
if (redirectTo !== "") {
redirect(redirectTo)
}
};
これでエラーの発生は避けられます。
原因
redirect 関数の中身を node_modules から覗いてみると、以下のようになっています。
redirect.js
function redirect(url, type) {
if (type === void 0) type = "replace";
const actionStore = _actionasyncstorageexternal.actionAsyncStorage.getStore();
throw getRedirectError(url, type, // If we're in an action, we want to use a 303 redirect
// as we don't want the POST request to follow the redirect,
// as it could result in erroneous re-submissions.
(actionStore == null ? void 0 : actionStore.isAction) ? _redirectstatuscode.RedirectStatusCode.SeeOther : _redirectstatuscode.RedirectStatusCode.TemporaryRedirect);
}
上記のように、内部で throw をしエラーを発生させているので、try...catch の中や非同期関数の中で使用するとエラーが発生してしまいます。
Discussion