Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEXT-435] Minimal middleware (only NextResponse.next()), generates error on error pages in dev mode #44293

Closed
1 task done
w4zZz4p opened this issue Dec 23, 2022 · 24 comments · Fixed by #46303
Closed
1 task done
Labels
bug Issue was opened via the bug report template. kind: bug Confirmed bug that is on the backlog linear: next Confirmed issue that is tracked by the Next.js team.

Comments

@w4zZz4p
Copy link

w4zZz4p commented Dec 23, 2022

Verify canary release

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

Provide environment information

Operating System:
Platform: win32
Arch: x64
Version: Windows 10 Pro
Binaries:
Node: 16.17.0
npm: N/A
Yarn: N/A
pnpm: N/A
Relevant packages:
next: 13.1.0
eslint-config-next: N/A
react: 18.2.0
react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

Routing (next/router, next/navigation, next/link)

Link to the code that reproduces this issue

https://github.com/w4zZz4p/issue-nextjs-error-page

To Reproduce

npm install
npm run dev

open http://localhost:3000/page-does-not-exist

Describe the Bug

When there is empty global middleware created:

import { NextResponse } from 'next/server';

export function middleware(request) {
    // some rewrite logic for specific requests

    // all other requests pass-trough
    return NextResponse.next();
}

and when you visit any 404 page, error occurs:

Unhandled Runtime Error
Error: Invariant: attempted to hard navigate to the same URL /page-does-not-exist http://localhost:3000/page-does-not-exist

The issue appeared in version v13.0.7-canary.5.
Version v13.0.7-canary.4 works as expected.
My assumption its related to #43836

Expected Behavior

There should be no error as in any existing page for example http://localhost:3000/

Which browser are you using? (if relevant)

Chrome 108.0.5359.125 (Official Build) (64-bit)

How are you deploying your application? (if relevant)

No response

NEXT-435

@w4zZz4p w4zZz4p added the bug Issue was opened via the bug report template. label Dec 23, 2022
@rokasblekaitis
Copy link

same here

@mataspetrikas
Copy link

same here, the 404 hard navigate problem still persists in the next 13.1.1

@PauloMFJ
Copy link

PauloMFJ commented Jan 5, 2023

Same issue here from v13.0.7 to latest (v13.1.1). Any Middleware file even if just export function middleware() {} breaks 404 page.

@jankaifer jankaifer added the kind: bug Confirmed bug that is on the backlog label Jan 19, 2023
@github-actions github-actions bot added the linear: next Confirmed issue that is tracked by the Next.js team. label Jan 19, 2023
@joggienl
Copy link

I also experience issues on the production build, it is not just on dev. It seems to have to do with i18n and/or getStaticPaths in that situation but have not been able to get a clear view on what’s going on. Definitely something that happens just by having a middleware file.

@p-chan
Copy link

p-chan commented Jan 23, 2023

In my case, I excluded /404 in matcher and it worked.

@mohux
Copy link

mohux commented Jan 23, 2023

@p-chan would you please provide an example of how you did so?
kinda killing me here

@p-chan
Copy link

p-chan commented Jan 24, 2023

@mohux I'm sorry.
I thought it worked well, but I was wrong.

@joggienl
Copy link

joggienl commented Jan 24, 2023

Adding the 404 page to exclude from the matcher does not work indeed.

As I commented before, it is not just on dev. A build is broken as well.

If you have a dynamic page with getStaticProps and getStaticPaths the 404 page will not get loaded. Even if you return { notFound: true } from the getStaticProps it will not work. After a refresh it sometimes does.

If you remove the middleware.js file (or just rename it for testing sake) it will work as expected again.

Reason for mentioning it is that I think some things around middleware and navigating are not going well. Not just on dev but also in a production environment.

@jankaifer jankaifer added linear: next Confirmed issue that is tracked by the Next.js team. and removed linear: next Confirmed issue that is tracked by the Next.js team. labels Jan 31, 2023
@jankaifer jankaifer changed the title Minimal middleware (only NextResponse.next()), generates error on error pages in dev mode [NEXT-435] Minimal middleware (only NextResponse.next()), generates error on error pages in dev mode Jan 31, 2023
@Dupflo
Copy link

Dupflo commented Feb 2, 2023

Same issue on next 13.1.2. So I will follow the ticket and hope for a fix

@Dupflo
Copy link

Dupflo commented Feb 3, 2023

I potentially found a workaround

I am using getStaticProps and also using dynamic revalidation but also using fallback: 'blocking' to manage my path which mean that my app will look at my headless CMS api to fetch non existant path/page at build time.

Since I am doing a check based on process.env.npm_lifecycle_event which can tell if you are building or running your app

    if (process.env.npm_lifecycle_event === 'build')
      return {
        notFound: true
      }
    return {
      redirect: {
        destination: '/404',
        permanent: false,
      },
    }

Then if I am building my app I am returning notFound: true. Once I am running it will prefetch the path and then return my page to a my 404. I don't want it to be permanent since I am using dynamic revalidation.

With this check I can then avoid the following error

Error: redirect can not be returned from getStaticProps during prerendering

@wadehammes
Copy link

Can confirm this is happening as well. Had to downgrade to 13.0.6 to fix.

@joggienl
Copy link

joggienl commented Feb 3, 2023

It seems like that when you have a middleware file, it triggers internal routing handling more than once. I noticed when running nextjs from source the first run is "good" but the second triggers this behaviour. This will also happen in production builds obviously.

I am not good enough into the nextjs repo to know how to fix or say something more educated about it, but that is what I noticed. It might help 🙈 .

@derek-primumco
Copy link

Can confirm this is happening as well. Had to downgrade to 13.0.6 to fix.

I observe that, for a 404 page, any middleware (just a console.log statement) gets called 3 times in the latest Next.js version, leading to the invariant error.

In 13.0.6, the middleware only gets called once for the 404 page, and there's no error. Thanks to OP for identifying in which version the issue was introduced.

@jankaifer jankaifer added the bug label Feb 7, 2023
@feedthejim
Copy link
Contributor

feedthejim commented Feb 7, 2023

@damien can you look at this issue? Seems more apps have encountered the issue

@meesvandongen
Copy link
Contributor

Seems to have been introduced at #43836

Namely, this code was removed.

      // We don't update for 404 requests as this can modify
      // the asPath unexpectedly e.g. adding basePath when
      // it wasn't originally present
      initialData.page !== '/404' &&
      initialData.page !== '/_error' &&

@WoLfulus
Copy link

WoLfulus commented Feb 10, 2023

It's broken for me too. In my case I'm using the locale example from the docs (to always send to a locale subpath either detected or chosen by the user). The only way I can get a custom 404 to show without any errors is to remove the middleware, which breaks the whole thing for me.

The problem (at least in my case) seems to be that next.js will always think that the route is a middleware redirection (and thus requesting chunks/page/whatever.json then breaking). This is because since I'm always under a locale subpath, having a middleware will make a matcher match because of the optional locale group in the regex.

For example, with locales enabled:

export const config = {
  matcher: ["/", "/((?!_next/static|assets|favicon.ico).*)"],
};

Turns into the following in

const matchers = await Promise.resolve(

// Without middleware - thus why it works
[] 
// With middleware & i18n in config
[
  "^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))(|\\.json|\\/?index|\\/?index\\.json)?[\\/#\\?]?$",
  "^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))(?:\\/((?!_next\\/static|assets|favicon.ico).*))(.json)?[\\/#\\?]?$"
]

and

// With middleware & without i18n in config
[
  "^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/(\\/?index|\\/?index\\.json))?[\\/#\\?]?$",
  "^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/((?!_next\\/static|assets|favicon.ico).*))(.json)?[\\/#\\?]?$"
]

I thought and tried to work around it by adding the "known locales" to the matcher (and also how I found the above), but it seems that whenever you have locale support enable, the matcher won't even match locales at all because it's already on that regex group. Whatever you add to the matcher will end up being something like /(locale)?/(matcher) in the end.

I know it's not purely related to locales, but it's how I managed to get the error page to show in my case. I hope this at least helps debugging it further - I'm completely stuck without an error page right now because of this since I had to completely disable ours just to avoid switching the whole application to client-side locale redirection and keep the behavior working.

@WoLfulus
Copy link

WoLfulus commented Feb 10, 2023

A poor workaround that worked for me is to just fallback rewrite to a custom error page and remove 404.tsx. The only con here is that it won't respond with 404, but with 200 instead.

module.exports = {
  // ...
  rewrites() {
    return {
      fallback: [
        {
          source: "/:path*",
          destination: "/not-found",
          locale: false,
        },
      ],
    };
  }
};

EDIT: To make it respond with 404, add getServerSideProps() to the custom error page and make it return { notFound: true }


Complete workaround

next.config.js

module.exports = {
  // ...
  rewrites() {
    return {
      fallback: [
        // last entry
        {
          source: "/:path*",
          destination: "/404bug?path=:path*",
          locale: false,
        },
      ],
    };
  },
};

middleware.js

// The contents of this file actually doesn't matter. 
// It just needs to exist and be a valid middleware to trigger the bug.
import { NextResponse } from 'next/server';
export function middleware(request) {
    return NextResponse.next();
}

pages/404.jsx

export default () => <div>404 works</div>;

pages/404bug.jsx

export default () => null;
export const getServerSideProps = () => ({ notFound: true });

@Eronheit
Copy link

If this helps resolve the issue, i'm using next version 12.2.0.

What worked for me was downgrading to the version 12.1.6, as described in:
#38239 (comment)

@wadehammes
Copy link

Any progress on a fix for this? Solution by @WoLfulus did not work for me.

@RioChndr
Copy link

I got this issue when using middleware and NextResponse.rewrite(url). when url is not found the issue is appear. I'm using custom route and page.

The temporary solution is downgrade to next@13.0.6, and it works as well.

MarekBodingerBA pushed a commit to bratislava/mestskakniznica.sk that referenced this issue Feb 22, 2023
MarekBodingerBA added a commit to bratislava/mestskakniznica.sk that referenced this issue Feb 22, 2023
* Fix link in 404

* Downgrade Next to 13.0.6

vercel/next.js#44293

---------

Co-authored-by: Marek Bodinger <marek.bodinger@gmail.com>
@gentlementlegen
Copy link
Contributor

gentlementlegen commented Feb 23, 2023

I concur with @RioChndr the issue doesn't arise in next@13.0.6.
On my case, it would manifest as the page reloading every second in dev mode, and when deployed, only once but breaking the page content while using next@13.1.6.

shuding added a commit that referenced this issue Feb 23, 2023
@kodiakhq kodiakhq bot closed this as completed in #46303 Feb 23, 2023
kodiakhq bot pushed a commit to AndyBitz/next.js that referenced this issue Feb 23, 2023
Closes vercel#44293.

## Bug

- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md)

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] [e2e](https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md)

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm build && pnpm lint`
- [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
@mamlzy
Copy link

mamlzy commented Mar 6, 2023

still facing the same issue..

@7iomka
Copy link
Contributor

7iomka commented Mar 10, 2023

:(

@github-actions
Copy link
Contributor

github-actions bot commented Apr 9, 2023

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 9, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template. kind: bug Confirmed bug that is on the backlog linear: next Confirmed issue that is tracked by the Next.js team.
Projects
None yet
Development

Successfully merging a pull request may close this issue.