admin管理员组

文章数量:1134549

My /app/api/auth/route.ts file:

import { redirect } from 'next/navigation';
    
export async function GET(req: Request) {
  try {
    redirect('/dashboard');
  } catch (error) {
    console.log(error);
    redirect('/');
  }
}

I realized that when I do redirect in a try catch, I get the error :

Error: NEXT_REDIRECT
        at getRedirectError (webpack-internal:///(sc_server)/./node_modules/next/dist/client/components/redirect.js:40:19)
        at redirect (webpack-internal:///(sc_server)/./node_modules/next/dist/client/components/redirect.js:46:11)
        at GET (webpack-internal:///(sc_server)/./app/api/auth/route.ts:23:66)
        at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
        at async eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:244:37) {
      digest: 'NEXT_REDIRECT;replace;/dashboard'
    }

When I get get rid of the try catch everything works fine:

export async function GET(req: Request) {
  redirect('/dashboard')
}

This works as expected. I need try and catch because this is an auth route and I need some error handling because the request could fail, I have left out the auth functionalities because I realized that this happens just on a simple try and catch.

Or if Next 13 has another way of error handling in /api routes please let me know.

My /app/api/auth/route.ts file:

import { redirect } from 'next/navigation';
    
export async function GET(req: Request) {
  try {
    redirect('/dashboard');
  } catch (error) {
    console.log(error);
    redirect('/');
  }
}

I realized that when I do redirect in a try catch, I get the error :

Error: NEXT_REDIRECT
        at getRedirectError (webpack-internal:///(sc_server)/./node_modules/next/dist/client/components/redirect.js:40:19)
        at redirect (webpack-internal:///(sc_server)/./node_modules/next/dist/client/components/redirect.js:46:11)
        at GET (webpack-internal:///(sc_server)/./app/api/auth/route.ts:23:66)
        at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
        at async eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:244:37) {
      digest: 'NEXT_REDIRECT;replace;/dashboard'
    }

When I get get rid of the try catch everything works fine:

export async function GET(req: Request) {
  redirect('/dashboard')
}

This works as expected. I need try and catch because this is an auth route and I need some error handling because the request could fail, I have left out the auth functionalities because I realized that this happens just on a simple try and catch.

Or if Next 13 has another way of error handling in /api routes please let me know.

Share Improve this question edited Mar 31, 2024 at 16:07 Michael M. 11.1k11 gold badges21 silver badges43 bronze badges asked May 6, 2023 at 21:52 AidenhsyAidenhsy 1,5713 gold badges21 silver badges42 bronze badges 4
  • 2 Did you end up figuring this out? I'm running into the same issue except it doesn't work outside the try catch either... Mine is in a dynamic route [id] not sure if that's causing it – Bash Commented Jun 5, 2023 at 20:09
  • I also ran into the same issue. I ended up using appRouter, instead. I read in the documentation that redirect returns an an NEXT_REDIRECT nextjs.org/docs/app/api-reference/functions/redirect#example, but i don't understand why and I don't understand how it is supposed to be used. – Kyle Angelo Gonzales Commented Aug 30, 2023 at 13:51
  • 1 I got this while using it in a Promise resolution's then callback. I realized this is a client component so I changed to useRouter and router.push instead. – ADTC Commented Nov 29, 2023 at 15:50
  • 1 why do they make a method redirect you cannot call without getting an error? Redirecting is just about the most basic thing you can do in a web app. And they make this complicated too? We should go back to vanilla JS it seems – Bersan Commented Feb 11, 2024 at 22:05
Add a comment  | 

20 Answers 20

Reset to default 60

When using redirect in a server component you should move it to the finally block. Here is how:

export default async function Page() {
    let redirectPath: string | null = null

    try {
        //Rest of the code
        redirectPath = `/dashboard`
    } catch (error) {
        //Rest of the code
        redirectPath = `/`
    } finally {
        //Clear resources
        if (redirectPath)
            redirect(redirectPath)
    }

    return <>{/*Rest of JSX*/}</>
}

From the redirect documentation:

redirect internally throws an error so it should be called outside of try/catch blocks.

In api routes you should use the NextResponse from next/server. Here is how

import { NextRequest, NextResponse } from "next/server";

export function GET(request: NextRequest) {
    try {
        //Code
        return NextResponse.redirect(`<an absolute url>`)
    } catch {
        //Error handling code
        return NextResponse.redirect(`<an absolute url>`)
    } finally {
        //Clear resources
        //No redirect here
    }
}

At the moment, the workaround I found is to not use:

import { redirect } from 'next/navigation';

But to use instead:

import { useRouter } from 'next/navigation'
const router = useRouter()
router.push("/")

It's easy to fix it. Currently, there is a bug in try-catch block with Next redirect. But you don't need to change anything. You just need to transfer try-catch block to different function. I can give you an example of my code:

"use server";
import LoginSchema from "@/Schemas/LoginSchema";
import PocketBase from "pocketbase";
import { redirect } from "next/navigation";

const analyze = async (data) => {
  const pb = new PocketBase("http://127.0.0.1:8090");
  try {
    const authData = await pb
      .collection("UserTable")
      .authWithPassword(await data.Email, await data.Password);
    if (authData) {
      return authData;
    }
  } catch (error) {
    error;
  }
};

export async function LoginAction(data) {
  const result = await LoginSchema.isValid(await data);
  if (result === true) {
    const result = await analyze(data);
    if (result) {
      return redirect("/");
    } else {
      return "failed";
    }
  } else {
    return "failed";
  }
}

This is because internally, redirect() is throwing an Error. See https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect.ts#L16-L41C2

The redirect function works by throwing a specific type of error caught by NextJS. The try/catch block 'catches' the error preventing the redirect from working.

If you are using redirect inside a try block, you can simply re-throw any redirectError in the catch block to achieve normal behaviour.

eg:

try {
    doSomethingThatCouldError()
    redirect("/dashboard")
  } catch(error) {
    // If redirect call this will re-throw it
    rethrowIfRedirectError(error)
    // Handle any other error as normal
    console.log(error)
}

Where the reusable rethrowIfRedirectError function is defined elsewhere as:

import { isRedirectError } from "next/dist/client/components/redirect"

export function rethrowIfRedirectError(error: unknown) {
  if (isRedirectError(error)) {
    throw error
  }
}

The redirect() is never supposed to be used in try/catch blocks. Here is a screenshot from the official docs: screenshot of nextjs documentation about redirect()

use
return NextResponse.redirect(new URL('/home', request.url))

in next 13+ app dir server side

The error that I got was Uncaught (in promise) Error: NEXT_REDIRECT

And I'm not sure if this is a bug... Because the method needs context info that is available inside "react render time!".

So this will work if you create a reference to use it later.

import { useRouter } from 'next/navigation'

function reactFunctionComponent() {
  const router = useRouter()
  runWithPromise().then( () => router.push("/") )
  ...
}

More info

Do this instead.

import { redirect } from 'next/navigation';

export async function GET(req: Request) {
  try {
    // Other logic
  } catch (error) {
    console.log(error);
    redirect('/');
  }

  redirect('/dashboard');
}

Internally, redirect throws an error as mentioned here. Hence, you should not catch it nor return it.

This happened to me when I used a try...catch statement. Rewrote my code in a way that didn't need a try...catch statement and it now works fine. This doesn't necessarily happen to API route files only, could happen in a react component where redirect is called inside a try catch.

this is redirect function:

function redirect(url, type) {
    if (type === void 0) type = "replace";
    throw getRedirectError(url, type, false);
}

this is getRedirectError()

function getRedirectError(url, type, permanent) {
    if (permanent === void 0) permanent = false;
    const error = new Error(REDIRECT_ERROR_CODE);
    error.digest = REDIRECT_ERROR_CODE + ";" + type + ";" + url + ";" + permanent;
    const requestStore = _requestasyncstorageexternal.requestAsyncStorage.getStore();
    if (requestStore) {
        error.mutableCookies = requestStore.mutableCookies;
    }
    return error;
}

Finally this is REDIRECT_ERROR_CODE IN getRedirectError:

const REDIRECT_ERROR_CODE = "NEXT_REDIRECT";

As you see, redirect() throws an error and next.js watches for this error and redirects the user. so when you put redirect inside a try/catch block, catch block catches this error. that is why you see the error. solution is put the redirect outside try/catch block

this feature is similar in sveltekit. in sveltekit we explicitly throw the redirect. maybe next.js should be more explicit. This can make the code more understandable to other programmers, and it can also make it easier to debug and maintain. in sveltekit:

export const GET: RequestHandler = () => {
    throw redirect(307,`URL`
}

You can use server actions with client-side, check this link in nextjs doc

 export async function appRedirect(route: string) {
      redirect(route)
    }

    // use it with async-await
    await appRedirect()

As @Daniel De León said the function needs to run in a react component. A clean workaround is to return the redirect call. ex:

function redirectUser(user) {
  if(user.isAdmin) {
    return redirect('/dashboard');
  } else {
    return redirect('401');
  }
}

export default async function ServerComponent(user){
  await redirectUser(user);
}

Just return the response then redirect in a file that does not have a try catch block.So this could be the client or server component where the response goes

If anyone faced this issue, use isRedirectError() function which returns true if the error is generated by redirect().

import { redirect } from 'next/navigation';

export async function GET(req: Request) {
  try {
    redirect('/dashboard');
  } catch (error) {
    // Do nothing if the error is generated by the redirect()
    if (!isRedirectError(error)) {
      console.log(error);
      redirect('/');
    }
  }
}

For me I was calling a function with the redirect inside of it, after moving it to the main page component everything worked.

change:


const someFunction = () => {
  redirect("/1234")
}

export default async function Page({
  return someFunction()
})

to this:

export default async function Page({
  return redirect("/1234")
})

You can also check if the error is a redirect error and "rethrow" it.

import { isRedirectError } from 'next/dist/client/components/redirect';
import { redirect } from 'next/navigation';
    
export async function GET(req: Request) {
  try {
    redirect('/dashboard');
  } catch (error) {
    if (isRedirectError(error)) throw error;
    redirect('/');
  }
}

Keep in mind though that this is an internal function and has no documentation etc. (besides JSDoc)

you can work with redirect like that:-

catch (error){

  let errorMessage = "An unknown error occurred";

  errorMessage = JSON.stringify(error, null, 2); 

   if (errorMessage.includes("NEXT_REDIRECT;push")) {
     toast.success("success case");
   }
  else{
    toast.error("Failure case");
  }

If the redirect() function in Next.js is causing an error but still manages to perform the redirection, it’s likely due to how it's being used or the context of its invocation. This issue usually arises when the redirect is not being handled as expected in a server-side action or during navigation.

Now you can do permenentRedirect with Next ^15. This can be used in Server Components, Client Components, Route Handlers, and Server Actions.

import { permanentRedirect } from 'next/navigation'
 
async function fetchTeam(id) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}
 
export default async function Profile({ params }) {
  const team = await fetchTeam(params.id)
  if (!team) {
    permanentRedirect('/login')
  }
 
  // ...
}

https://nextjs.org/docs/app/api-reference/functions/permanentRedirect

After hours of struggling I found a solution: I added the below code to the catch block:

if (isRedirectError(error)) {
      throw error;
    }

本文标签: javascriptNext 134 Error NEXTREDIRECT in API routesStack Overflow