'm working on a Next.js application and have a login form that handles user sign-in. I use the redirect function from next/navigation for server-side redirection after a successful sign-in. However, I'm encountering the following error:
Sign-in error: Error: NEXT_REDIRECT
at getRedirectError (redirect.js:49:19)
at redirect (redirect.js:60:11)
at handleSignIn (cognitoActions.ts:87:13)
at async eval (login-form.tsx:38:34)
Here is my current code setup:
LoginForm component:
import React, { useTransition } from 'react'
import { Button } from '../button'
import { Input } from '../input'
import Link from 'next/link'
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { TLoginSchema } from '@/lib/types/LoginSchema'
import { loginSchema } from '@/lib/schemas/login'
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
import { handleSignIn } from '@/lib/cognitoActions'
export default function LoginForm() {
const [pending, startTransition] = useTransition()
const form = useForm<TLoginSchema>({
resolver: zodResolver(loginSchema),
defaultValues: {
email: '',
password: '',
},
})
function onSubmit(values: TLoginSchema) {
startTransition(async () => {
try {
const response = await handleSignIn(undefined, values)
console.log('Sign-in response:', response)
} catch (error) {
console.error('Sign-in error:', error)
}
})
}
return (
<Form {...form}>
<form className='flex flex-col justify-between gap-8 min-w-[450px]' onSubmit={form.handleSubmit(onSubmit)}>
<h1>Chat Inmobiliario</h1>
<FormField
control={form.control}
name='email'
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input type='email' {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='password'
render={({ field }) => (
<FormItem>
<FormLabel>Contraseña</FormLabel>
<FormControl>
<Input type='password' {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button size='lg' type='submit' disabled={pending}>
{pending ? 'Ingresando...' : 'Ingresar'}
</Button>
</form>
</Form>
)
}
handleSignIn function:
import { signUp, confirmSignUp, autoSignIn, resendSignUpCode, signIn, signOut } from 'aws-amplify/auth'
import { TLoginSchema } from './types/LoginSchema'
import { TSignUpSchema } from './types/SignUpSchema'
import { getErrorMessage } from '@/utils/get-error-message'
import { redirect } from 'next/navigation'
import { TConfirmSignupSchema } from './types/ConfirmSignupSchema'
export async function handleSignIn(prevState: string | undefined, formData: TLoginSchema) {
let redirectLink = '/dashboard'
try {
const { isSignedIn, nextStep } = await signIn({
username: String(formData.email),
password: String(formData.password),
})
if (nextStep.signInStep === 'CONFIRM_SIGN_UP') {
console.log(nextStep.signInStep)
await resendSignUpCode({
username: String(formData.email),
})
redirectLink = '/auth/confirm-signup'
}
} catch (error) {
return getErrorMessage(error)
}
console.log('Redirecting to:', redirectLink)
redirect(redirectLink)
}
Despite using redirect in a server-side context, I still encounter the NEXT_REDIRECT error. How can I correctly handle redirection on the server side without encountering this error? What am I doing wrong in my implementation?
I think what's happening is that your code is actually executing in the client. I don't see a 'use client'
directive in your LoginForm
component but since you are using hooks in there (which can only be used client side) and the component renders ok I'm guessing you have the use client
in some parent component that imports the LoginForm
component and therefore LoginForm
is treated as a client component.
Since handleSignIn
is running client side it makes sense that you see that error given that redirect
is meant to be called server side. Two things you can do to fix this are:
replace redirect
with router.push
or router.replace
from useRouter. This is basically a workaround to redirect
in the client.
refactor your useSignin
function as a server action and add it in your form as an action instead of handling the submit event.