Next.js: 404 error when using useFileSystemPublicRoutes = false

Created on 30 Jul 2017  Β·  24Comments  Β·  Source: vercel/next.js

When useFileSystemPublicRoutes is set to false and there is no custom route for path, but page-based route exists, nextjs will render that page on client instead of 404.

Steps to reproduce:

  1. Take custom-server example
  2. Replace const app = next({ dev }) in server.js with
    const app = next({ dev, conf: { useFileSystemPublicRoutes: false } })
  3. There's now no route for /
  4. Start the server, hit localhost:3000
  5. Server serves 404 (it flashes for a moment), then client takes over and re-renders /pages/index.js component. Browser console contains Warning: React attempted to reuse markup

So with this option behavior on server and client is not consistent, and it doesn't look like it should work this way.

bug

Most helpful comment

also seeing the same problem, any updates on this issue? thanks

All 24 comments

I've also run into this issue.

This useFileSystemPublicRoutes: false seems to be useless β€”Β it stops the server from setting up matching routes for the file names, but the next client still attempts to use a PageLoader to pull in the chunk for the file-named pathname at runtime.

So when a request comes in for a named page e.g. pages/foo.js:

  1. Server correctly 404s
  2. _error component is correctly rendered
  3. Next client attempts to fetch the chunk for /foo (this shouldn't happen)
  4. Client-side re-renders, causing chaos

What should _probably_ happen is that when _error is rendered, it should have the same behaviour as if pages/foo.js doesn't exist.
This is tough though, as you will probably still want to load the foo.js chunk on anotherβ€”validβ€”page.

One solution is that a flag is passed down to the error page, so it doesn't attempt to load a named chunk (foo.js in our case), but just the error chunk.
This will solve the flash-404, but this won't work for client-side routing (where the client wouldn't start from an error page).

But this would be fine as long as you don't make a bad link.

I'll give it a go and open a PR.

Any updates on this? I'm using a custom server to point /:username to ./pages/user.js, but like what @GennadyPonomarev & @iest have described, it didn't work as expected.

Hmm seems I did it wrong, this could fix my issue:

server.get('/:username', (req, res) => {
 app.render(req, res, '/user', { 
    username: req.params.username 
  })
})

My app:

<Link href="/user?username=egoist" as="/egoist">
  <a>egoist</a>
</Link>

I just ran into this as well, playing with one of the examples (ssr caching) to make it use koa.

In the example, /blog should be invalid, and /blog/first should work.

useFileSystemPublicRoutes = false

is ignored by the client-side code.

I worked around the problem by renaming pages/blog.js to pages/blog2.js and fixing my code a bit, just to hide /blog a little better. So now at least /blog is a proper Next 404, but /blog2 is still available and it's a mix of my blog2.js content and formatted as a Next error page.

I've got a small example at https://ssr-caching-koa-amateehwho.now.sh/ (and source).

useFileSystemPublicRoutes is set false in next.config.js.

First, the actual problem can be seen at https://ssr-caching-koa-amateehwho.now.sh/blog2. Note that there is a /pages/blog2.js file.

A correct 404 is https://ssr-caching-koa-amateehwho.now.sh/blog. We have no /pages/blog.js file.

Actual posts are at https://ssr-caching-koa-amateehwho.now.sh/blog/first for example but I'm making use of a custom server to handle routing and map /blog/:id to the /pages/blog2.js file (passing the id parameter).

I solved this problem changing the end of the default export of /client/index.js to:

if (props && props.statusCode === 404) { // here
  return emitter                         // here
}                                        // here

router.subscribe(({ Component, props, hash, err }) => {
  render({ Component, props, err, hash, emitter })
})

const hash = location.hash.substring(1)
render({ Component, props, hash, err, emitter })

return emitter

So if the client receives 404 from the server, it stops trying to render the page again. I am not sure if this is the best approach as I am not familiar with the lib. To me, an even better solution would be to prevent the client from re-rendering error pages.

This seems to be a problem that needs to be addressed. Why no updates in over 6 months?

@rafaelalmeidatk I don't get your code. The props variable doesn't seem to exist outside of subscribe function.

@iest Any update on your fix?

thanks.

also seeing the same problem, any updates on this issue? thanks

I'm currently still experiencing this in 5.0.0.

@timneutkens I see you've added the label: good first issue. Do you have any pointers on where to look for this?

I'll try to submit a PR to fix this.

@thomhos it's actually not easy to fix, removed the label πŸ‘, I'd have to investigate it further to come up with a solution.

Ah, I just submitted a PR which seems to fix the problem for me as far as I could test locally. I guess we should close that as well?

I encountered the same problem in 5.0.0

Any updates? This is a very annoying issue.

@gcpantazis The problem is that you can have something like

.
└── pages
    └── dashboard
    β”‚   └── index.js
    └── landing
        └── index.js

And then have some custom routing like:

router.get('/', (req, res) => {
  if (!req.isAuthenticated()) {
    return next.render(req, res, '/dashboard', req.query);
  }
  next.render(req, res, '/landing', req.query);
});

So that logged-out users see a landing view, and logged-in users see a dashboard.

This works fine when hitting / as expected.

But if any user goes to /dashboard or /landing they will see these views (though it will likely throw some errors along the way). The expected behavior is that by setting useFileSystemPublicRoutes: false the routes _must_ be defined manually, but they are still accessible via the browser.

@tmarshall Apologies, you're right; I deleted my comments to avoid confusion. I had some ideas on the way home, so I'll make a test project to see if we can suss out a proposal to fix this. πŸ™Œ

For what it's worth, it looks like the case mentioned by most of the reporters here (i.e., server renders a 404s then flashes to an unexpected client-rendered page) was fixed incidentally as of 5.0.1-canary.5 (and specifically by #3749).

There's a few other cases that we could consider:

Explicit navigation:

1) Create a Link that corresponds to a file-system route, even though you disabled it via useFileSystemPublicRoutes.
2) Click on that Link.
3) See the page, even though useFileSystemPublicRoutes: false implies you shouldn't.

popstate:

1) Go to a URL that corresponds to a file-system route, even though you disabled it via useFileSystemPublicRoutes. Get a 404 from SSR.
2) Click on a link that takes you something else via client-side navigation.
3) Hit "back" on the browser.
4) You'll see the file-system route render instead of a 404.

Of the two, I'd say the first is maybe not a huge concern, since as you've opted to replace Next's default routing you should be responsible for client-side navigation to bad URLs. The second I think is a bigger issue (and perhaps can be a separate issue, since as far as I can tell most of the reporters' problems will be resolved in 5.0.1).

Test case here: https://github.com/gcpantazis/nextjs-playground/tree/useFileSystemPublicRoutes

@thomhos made a PR for it: https://github.com/zeit/next.js/pull/3777
@gcpantazis could you try out the PR?

Rebased and tried that patch, @timneutkens. Unfortunately I think #3777 only fixes the issue described here because it breaks client-side altogether (removes the route to the bundles, i.e. ['/_next/:buildId/page/:path*.js'] if useFileSystemPublicRoutes: false).

I think I have an alternate solution; I'll put it together when I get to the office.

Hi guys, I realize now as well that #3777 was a very naive approach to the problem, I was hoping to kickstart it a bit and come to a solution together :)

Let me know if you need any help, I haven't looked into this for a while.

@timneutkens ping on ☝️ before it gets stale! πŸ™‡

The case mentioned in the issue topic is actually solved in next@canary. Thanks new 404 logic.

Creating a new issue for @gcpantazis's comments on other cases.

4008

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lixiaoyan picture lixiaoyan  Β·  3Comments

irrigator picture irrigator  Β·  3Comments

formula349 picture formula349  Β·  3Comments

wagerfield picture wagerfield  Β·  3Comments

timneutkens picture timneutkens  Β·  3Comments