Error: NEXT_REDIRECT #9389
-
using next-auth": "^5.0.0-beta.4. The problem is the error "NEXT_REDIRECT" it occurs every time I try to wrap methods singIn, singOut in a try catch block, in this case login happens, data is written to the session, but redirection does not happen. After refreshing the page my middleware redirects normally, and the data is there, I try to exit through signOut which is wrapped in try catch, again the exit occurs normally, but no redirection occurs. CODEauth.jsexport const {
signIn,
signOut,
auth
} = NextAuth({
...authConfig,
providers: [
CredentialsProvider({
async authorize(credentials) {
try {
const user = {username: 'test', email: 'test'}
return user;
} catch (err) {
console.log('authorize error:', err)
return null;
}
},
}),
],
callbacks: {
async jwt({ token, user }) {
if (user) {
token.username = user.username;
token.img = user.img;
}
return token;
},
async session({ session, token }) {
if (token) {
session.user.username = token.username;
session.user.img = token.img;
}
return session;
},
},
}); authconfig.jsexport const authConfig = {
providers: [],
pages: {
signIn: "/login",
},
callbacks: {
async authorized({ auth, request }) {
console.log('============================================');
const isLoggedIn = auth?.user;
const isOnDashboard = request.nextUrl.pathname.startsWith("/dashboard");
console.log('auth:', auth, 'isLoggedIn', isLoggedIn, 'isOnDashboard', isOnDashboard)
if (isOnDashboard) {
if (isLoggedIn) return true;
return false;
} else if (isLoggedIn) {
return Response.redirect(new URL("/dashboard", request.nextUrl));
}
return true;
},
},
}; This is the basic structure, here's how I try to use it in LoginForm import styles from "./loginForm.module.css";
import { signIn } from "@/app/auth";
const LoginForm = () => {
return (
<form action={async (formData) => {
"use server"
try {
await signIn("credentials", formData);
}
catch (e) {
console.log(e);
}
}} className={styles.form}>
<h1>Login</h1>
<input type="text" placeholder="username" name="username" />
<input type="password" placeholder="password" name="password" />
<button>Login</button>
</form>
);
};
export default LoginForm; And in this case if I use try catch I get an error. Full errorError: NEXT_REDIRECT
at getRedirectError (webpack-internal:///(rsc)/./node_modules/next/dist/client/components/redirect.js:44:19)
at redirect (webpack-internal:///(rsc)/./node_modules/next/dist/client/components/redirect.js:54:11)
at signIn (webpack-internal:///(rsc)/./node_modules/next-auth/lib/actions.js:62:89)
at async $$ACTION_1 (webpack-internal:///(rsc)/./app/ui/login/loginForm/loginForm.jsx:69:9)
at async D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:38:489
at async tX (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:37:5313)
at async rl (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:38:23339)
at async doRender (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\server\base-server.js:1406:30)
at async cacheEntry.responseCache.get.routeKind (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\server\base-server.js:1567:28)
at async DevServer.renderToResponseWithComponentsImpl (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\server\base-server.js:1475:28)
at async DevServer.renderPageComponent (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\server\base-server.js:1852:24)
at async DevServer.renderToResponseImpl (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\server\base-server.js:1890:32)
at async DevServer.pipeImpl (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\server\base-server.js:902:25)
at async NextNodeServer.handleCatchallRenderRequest (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\server\next-server.js:266:17)
at async DevServer.handleRequestImpl (D:\Person\Edvard\Desktop\nextadmin\node_modules\next\dist\server\base-server.js:798:17) {
digest: 'NEXT_REDIRECT;replace;http://localhost:3000/login?callbackUrl=http%3A%2F%2Flocalhost%3A3000%2Fdashboard;false',
mutableCookies: p {
_parsed: Map(6) {
'next-auth.csrf-token' => [Object],
'authjs.csrf-token' => [Object],
'next-auth.callback-url' => [Object],
'next-auth.session-token' => [Object],
'authjs.callback-url' => [Object],
'authjs.session-token' => [Object]
},
_headers: HeadersList {
cookies: [Array],
[Symbol(headers map)]: [Map],
[Symbol(headers map sorted)]: null
}
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 16 comments 24 replies
-
I noticed that the catch block in your form's action async function is currently logging the error to the console but not re-throwing it. This could be causing the issue you're encountering. Try to add "throw e" in catch.
|
Beta Was this translation helpful? Give feedback.
-
This is crazy. What's the point of having the framework + auth library when such simple stuff don't work built-in? |
Beta Was this translation helpful? Give feedback.
-
This library is literally is a garbage. |
Beta Was this translation helpful? Give feedback.
-
In my case I removed the try catch and let me redirect to /* eslint-disable import/no-extraneous-dependencies */
'use server';
import { signIn } from '@/auth';
export async function sendUhOidAction(
prevState: {
message: string;
},
email: string,
) {
// try {
await signIn('credentials', {
email,
redirectTo: '/test',
});
// return undefined;
// } catch (error) {
// console.log({ error });
// if (error instanceof Error) {
// const { type, cause } = error as AuthError;
// switch (type) {
// case 'CredentialsSignin':
// return 'Invalid credentials.';
// case 'CallbackRouteError':
// return cause?.err?.toString();
// default:
// return 'Something went wrong.';
// }
// }
// throw error;
// }
} |
Beta Was this translation helpful? Give feedback.
-
After hours of struggling I found a solution: |
Beta Was this translation helpful? Give feedback.
-
Hi, still failing for me import { Button, Input, Label } from '$ui'
import { SigninHeader } from '$/app/signin/layout'
import { signIn } from '$/auth'
import { PageProps } from '$/lib/types'
import { isRedirectError } from 'next/dist/client/components/redirect'
export default async function SignInPage(props: PageProps<'', 'callbackUrl'>) {
const callbackUrl = String(props.searchParams.callbackUrl ?? '/')
return (
<>
<SigninHeader
title='Access your books'
description='Enter your email below to see your books.'
/>
<form
action={async (formData) => {
'use server'
try {
await signIn('nodemailer', {
callbackUrl,
email: formData.get('email')?.toString()!,
})
} catch (error) {
if (isRedirectError(error)) {
console.log('FUCK!: ', error)
throw error
}
}
}}
>
<div className='grid gap-2'>
<div className='grid gap-1'>
<Label className='sr-only' htmlFor='email'>
Email
</Label>
<Input
autoFocus
required
id='email'
name='email'
placeholder='Your email address'
type='email'
autoCapitalize='none'
autoComplete='email'
autoCorrect='off'
/>
</div>
<Button>Sign In with Email</Button>
</div>
</form>
</>
)
}
DebuggingDebugging the code I think https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/lib/actions.ts#L76 That gets the URL from If I put a log in [auth][debug]: Error in Auth "Redirecting to http://localhost:3003/api/auth/error?error=Configuration and isRedirect=false" But then here if (shouldRedirect) return redirect(res.redirect!)
Which makes sense with what I see in the logs The docs for custom signin page could be improved covering error handling |
Beta Was this translation helpful? Give feedback.
-
I can confirm. If I hack this line with a hardcoded URL it redirects to the error page - if (shouldRedirect) return redirect(res.redirect!)
+ if (shouldRedirect) {
+ return redirect('http://localhost:3003/api/auth/error?error=Configuration');
+ } Now the question is why |
Beta Was this translation helpful? Give feedback.
-
I made a PR that I think it fix at least some cases when the error is of type |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
I came across this thread because I encountered what I initially thought was a similar issue when implementing credentials flow. This is my first time working with NextAuth and it turns out I missed the part in the doc that specifies that you need to explicitly set your session strategy to jwt: session: {
strategy: 'jwt'
}, Hopefully this will help someone else who runs into the same problem! |
Beta Was this translation helpful? Give feedback.
-
Hello! I have the same error this is my code
Any suggestions? Thanks! |
Beta Was this translation helpful? Give feedback.
-
Hey guys, I found a slight optimization to the homemade Next.js actually exposes a native "isRedirectError" function to check for this already, probably better to use for future breaking changes as well. Here's a basic working example: "use server";
import { signIn } from "~/auth";
import { isRedirectError } from "next/dist/client/components/redirect";
export default async function signInUser() {
try {
await signIn();
} catch (error: unknown) {
if (isRedirectError(error)) throw error;
// continue to handle other errors as normal
}
} |
Beta Was this translation helpful? Give feedback.
-
Issue Title: Form Submission Issue Resolved by Removing Redirect Code Description: I encountered an issue with form submission where the form was not behaving as expected. The problem was resolved by removing the redirect code within the Solution: Removing the following code resolved the issue: // if (result?.status === 200) {
// router.push("/");
// } |
Beta Was this translation helpful? Give feedback.
-
redirect() shouldn't be called in a try...catch... block. If you read the source code of nextjs, about redirect function: https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect.ts#L49 It throws The signIn function of Authjs uses this redirect function of nextjs, so you need to put it outside of try...catch... |
Beta Was this translation helpful? Give feedback.
-
Using next: 14.2.8 & next-auth: ^5.0.0-beta.20 I had the same error and after trying some of the proposed solutions I solved my problem by adding “redirect: false” in the options of the “signIn” method and since then I no longer have the error. Here's the code: ./src/configs/auth.ts import NextAuth from 'next-auth';
import credentials from 'next-auth/providers/credentials';
import bcrypt from 'bcrypt';
import { connectDB } from '@/configs/mongodb';
import User from '@/models/schemas/user';
import { IUserDocument } from '@/models/interfaces/documents';
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
credentials({
name: "Credentials",
id: "credentials",
credentials: {
email: { label: "Email", type: "text" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
await connectDB();
const user = await User.findOne<IUserDocument>({
email: credentials?.email,
}).select("+password");
if (!user) throw new Error("Wrong Email");
const passwordMatch = await bcrypt.compare(
credentials!.password as string,
user.password
);
if (!passwordMatch) throw new Error("Wrong Password");
return user;
},
}),
],
session: {
strategy: "jwt",
},
}); ./src/actions/authenticate.ts 'use server';
import { signIn } from '@/configs/auth';
import { AuthError } from 'next-auth';
export const authenticate = async (formData: FormData) => {
try {
await signIn("credentials", {
email: formData.get("email"),
password: formData.get("password"),
redirect: false
});
return { ok: true };
} catch (error) {
if (error instanceof AuthError) {
switch (error.type) {
case 'CredentialsSignin':
return {
error: true,
message: 'Invalid email or password.'
};
default:
return {
error: true,
message: error.message
};
}
}
throw error;
}
}; ./src/components/login/index.tsx 'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
import { authenticate } from '@/actions/authenticate';
const Login = () => {
const [error, setError] = useState("");
const router = useRouter();
const handleSubmit = async (formData: FormData) => {
const res = await authenticate(formData);
if (res?.error) {
setError(res?.message as string);
}
if (res?.ok) {
return router.push("/dashboard");
}
};
return (
<section className="w-full flex items-center justify-center">
<form
className="p-6 w-full max-w-[400px] flex flex-col justify-between items-center gap-2 border border-solid border-black bg-white rounded"
action={handleSubmit}>
[...]
);
};
export default Login; ./src/app/login/page.tsx import Login from '@/components/login';
export default function LoginPage() {
return <Login />;
}; |
Beta Was this translation helpful? Give feedback.
-
I got the same error, however I fixed it with this code: // ... server actions
try {
await signIn('credentials', {
email: formData.get('email'),
password: formData.get('password'),
redirect: true,
redirectTo,
});
} catch (error) {
if (isRedirectError(error)) {
console.error('Redirect error!: ', error);
throw error;
}
redirect(`/login?error=credentials`);
} |
Beta Was this translation helpful? Give feedback.
EDIT - I figured out a solution, add the following code to the catch block in the authenticate action:
I am slightly confused why it's necessary to throw e; when I want to be able to send messages back to the client:
// action.ts