next.js icon indicating copy to clipboard operation
next.js copied to clipboard

307 redirect loop when using locale together with middleware in 13.5.1

Open c0per opened this issue 1 year ago • 31 comments

Link to the code that reproduces this issue

https://github.com/c0per/307-loop-i18n-middleware

To Reproduce

  1. set defaultLocale to something different than preferredLocale (from header accept-language)
  2. npm run dev
  3. access http://localhost:3000/en or http://localhost:3000/fr or http://localhost:3000 or with trailing slash

Current vs. Expected behavior

image

Currently, Next.js 13.5.1 will stuck in 307 loop if:

  • turn on localeDetection (which is enabled by default)
  • set defaultLocale different from user's preferredLocale
  • use a middleware

Expected behavior:

It doesn't stuck.

Verify canary release

  • [X] I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: x64
      Version: Darwin Kernel Version 22.6.0: Wed Jul  5 22:21:56 PDT 2023; root:xnu-8796.141.3~6/RELEASE_X86_64
    Binaries:
      Node: 18.16.0
      npm: 9.5.1
      Yarn: 1.22.19
      pnpm: N/A
    Relevant Packages:
      next: 13.5.1
      eslint-config-next: 13.5.1
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.2.2
    Next.js Config:
      output: N/A

Which area(s) are affected? (Select all that apply)

Internationalization (i18n)

Additional context

No response

c0per avatar Sep 20 '23 09:09 c0per

I tried to track down this bug.

(I'm not sure about the following investigation)

  1. When accessing localhost:3000/en, nextjs do a "internal" redirect to / with locale set to en. Won't send redirect request to browser
  2. Then nextjs will handle / request.

Now detectedLocale becomes preferredLocale (accept-language, in this case en). (No pathLocale, no domainLocale, no locale from cookie) image

Since detectedLocale (en) !== defaultLocale (fr in the example), nextjs will send a redirect request to localhost:3000/en. image

Thus it's stuck.

c0per avatar Sep 20 '23 09:09 c0per

The bug first appears in version 13.4.20-canary.24, 13.4.20-canary.23 is fine.

c0per avatar Sep 20 '23 10:09 c0per

Yup, I was waiting for the default locale fix (since it broke after 13.4.12) and now in 13.5.1 the documented default locale prefixing is broken resulting in an infinite loop. Mentioned this here as well. https://github.com/vercel/next.js/issues/54217#issuecomment-1727466409

SanderRuusmaa avatar Sep 20 '23 11:09 SanderRuusmaa

Similar issue https://github.com/vercel/next.js/issues/54495

philipheinser avatar Sep 20 '23 19:09 philipheinser

Same issue here, upgrading > 13.4.19 breaks the app with the 307 redirect loop.

Zerebokep avatar Sep 26 '23 15:09 Zerebokep

Same issue here. 307 redirect loops on /en after upgrading Next.js.

ioExpander avatar Sep 27 '23 17:09 ioExpander

same here

jeremymarc avatar Oct 11 '23 17:10 jeremymarc

Same issue here. I'm getting a redirect loop as well

Javimtib92 avatar Oct 17 '23 13:10 Javimtib92

We are having the same issue, but after testing the Canary releases, I saw the issue started on:

https://github.com/vercel/next.js/releases/tag/v13.4.20-canary.24

23 works as expected https://github.com/vercel/next.js/releases/tag/v13.4.20-canary.23

danielbarion avatar Oct 18 '23 12:10 danielbarion

Same issue. My guess is that this PR broke it: https://github.com/vercel/next.js/pull/54813/files

raRaRa avatar Oct 19 '23 14:10 raRaRa

An easy workaround would be turning off detectLocale.

Accessing /page will go to /${default locale}/page instead of /${accept-language header in user request}/page.

c0per avatar Oct 20 '23 05:10 c0per

Client-side routing is also broken with localization when middleware file is present. The locale always becomes the default locale when clicking on a <Link /> that routes to something such as https://page.com/de - it returns 404. If I do a refresh on that route (server-side routing) then it works.

raRaRa avatar Oct 20 '23 09:10 raRaRa

An easy workaround would be turning off detectLocale.

Accessing /page will go to /${default locale}/page instead of /${accept-language header in user request}/page.

this doesn't work

piekczyk avatar Oct 30 '23 12:10 piekczyk

Does the Next team even acknowledge this issue?

Seems to only affect the index route for me.

masnormen avatar Oct 31 '23 06:10 masnormen

Confirming that:

  • having i18n
  • having middleware
  • having the not default language set in the browser preferences
  • up to date next version

breaks the homepage view. Removing one of them fixes the issue (not a fix at all...). Removing locale detection breaks Link components (goes to default language on a page change).

marcinciarka avatar Oct 31 '23 11:10 marcinciarka

Based on how things are done in Nextjs App router, I don't really see a fix coming any time soon (almost feels like we're being pushed to the App router). I think the best way forward is to handle i18n manually, without having Nextjs do it magically.

That means you could follow the strategy on how it's being done in the App router:

  1. Create segment for languages, e.g. /pages/[language]/...
  2. Create page level context that stores the locale, so that you could do something like const { locale } = usePageContext() instead of using useRouter
  3. (optional) Use middleware to detect locale and URL re-write/redirect based on that.

raRaRa avatar Nov 01 '23 09:11 raRaRa

Just ran into this as well. No fix yet, not even an acknowledgement.

Having to deal with these kinds of issues with every patch- or minor-level Next.js upgrade is getting so frustrating and really makes me wonder if Next.js is still on the right trajectory. Putting that much energy into stuff like RSCs and leaving existing users in the dust with stuff like this will eventually come back to bite you, Vercel. Make the foundations work (middleware AND i18n in the same app is not that unusual, isn't it?), then move on to the fancy stuff.

soulchild avatar Dec 01 '23 06:12 soulchild

I have the same issue on v14.0.3 with the pages router. Turning off locale detection does fix the issue.

franknoel avatar Dec 01 '23 22:12 franknoel

I ended up removing all NextJS specific locales, which means I had to create a language slug for each language and do some other manual things. In the end it works better and is more bullet proof against breaking changes. This is also the way forward in the App router AFAIK.

raRaRa avatar Dec 02 '23 14:12 raRaRa

This just goes to show that people are losing faith in Vercel and Next.js, IMHO. If we can't use the features a framework provides out of fear they might break at any time, why use a (more fully featured) framework at all? Oh, sorry, I forgot: Streaming components, form fields submitting directly to functions... Who needs working I18n and middlewares if you can have the future™️? 😄

soulchild avatar Dec 04 '23 07:12 soulchild

here's something that has worked for us, maybe it will help someone too - In the i18n config, disable the nextJs locale detection, like:

{
  locales: ['en', 'de', 'ja'],
  defaultLocale: 'en',
  defaultNS: 'common',
  localeDetection: false,
 }

we handle the redirecting manually in our middleware and for the locale string we use the [email protected]

mataspetrikas avatar Dec 04 '23 16:12 mataspetrikas

I'm experiencing similar problems with middleware, next-i18next, pages router and the root URLs (i.e. /de, /sv, /en etc.). My problem is that the middleware function isn't called at all for the root URL (all other URLs not being on the root, like /en/whateverpage/ works)

Also i need to set trailingSlash: false in my next config otherwise the startpage won't work at all when having a middleware file.

My middleware matcher looks like this so this:

 {
      source: '/((?!api|_next/static|_next/image|favicon.ico).*)',
      missing: [
        { type: 'header', key: 'next-router-prefetch' },
        { type: 'header', key: 'purpose', value: 'prefetch' },
      ],
    },

In my case this prevents setting CSP rules for the startpage but it works for all other pages. Tried this with latest next version 14.0.4

valleywood avatar Dec 08 '23 14:12 valleywood

Hey @valleywood!

You're not alone; I'm also banging my head against the wall trying to get middlewares to play nicely with Next.js i18n… 😅

My problem is that the middleware function isn't called at all for the root URL (all other URLs not being on the root, like /en/whateverpage/ works)

I actually faced the exact same issue and was able to fix it simply by adding "/" to the array of matchers so my config looks like this:

export const config = {
  matcher: [
    "/", // Required when i18n is enabled, otherwise middleware won't be executed on index route
    "/((?!api/|_next/|_static/|_vercel|fonts|images/|[\\w-]+\\.\\w+).*)",
  ],
};

Hope that this will unblock you! 😉

Aiming to get a minimal reproducible example ready and open an issue in the coming days…

raphaelsaunier avatar Dec 08 '23 14:12 raphaelsaunier

@raphaelsaunier Thank you so much! 😍 Your code together with localeDetection: false actually solved my issue both with the middleware being called and not forcing me to use trailingSlash: false.

Was trying something similar like this before but wasn't able to get my regExp right I guess.

Sounds great if you are able to provide a reproduction repo because is would be good to have both middleware and localeDetection working simultaneously, now it seems one have to choose. 🙏

Have a wonderful weekend!

valleywood avatar Dec 08 '23 14:12 valleywood

@ijjk @timneutkens @huozhi do you guys have any ideas or thoughts about this?

danielbarion avatar Dec 08 '23 16:12 danielbarion

Facing the same problem thanks for pointing out a possible workaround (even if loosing language detection is not that great). I still however have problems even with the workaround as I still still some really strange redirects from middleware to localhost (in production!)

Also tried next 14 but have the same problem there, and other problems as well also regarding middleware :/ Its not looking good I wonder if really using i18n is at this point a bad idea..

that would be bad since this was promoted a lot as a great feature (which it totally is) in a nextjs conf.

joaogarin avatar Dec 12 '23 13:12 joaogarin

Same here. Have infinite redirect problem using next 14

EvilaMany avatar Jan 01 '24 12:01 EvilaMany

Would love to see an update on this so we can upgrade to v14 for now we are pinned to v13.

TrevorThomp avatar Jan 05 '24 19:01 TrevorThomp

@raphaelsaunier Thank you so much! 😍 Your code together with localeDetection: false actually solved my issue both with the middleware being called and not forcing me to use trailingSlash: false.

Was trying something similar like this before but wasn't able to get my regExp right I guess.

Sounds great if you are able to provide a reproduction repo because is would be good to have both middleware and localeDetection working simultaneously, now it seems one have to choose. 🙏

Have a wonderful weekend!

Hello, is it possible to provide us a complete example for disabling localeDetection without i18n, please?

Thanks in advance!

Best Loïc

LoicFpa974 avatar Jan 15 '24 15:01 LoicFpa974

Using [email protected]

Having the same 307 loop problem when localeDetection is true and using middleware. I don't want to disable the localeDetection because it is an amazing feature, that the user is automatically redirected to the right locale url.

But if I add a middleware.ts the 307 problem occurs.

// middleware.ts
export async function middleware(req: NextRequest) {
  console.log('hello')
}

lass-tanzen avatar Jan 19 '24 12:01 lass-tanzen