Vercel: 404 errors with dynamic routes in next.js and now

Created on 12 Nov 2019  ·  40Comments  ·  Source: vercel/vercel

I'm running into issues with a Next.js version 9.1.3 and now 16.4.4 where everything will deploy and work but I get a number of 404 errors for my apis and dynamic routes.

Nextjs dynamic routing error

My now.json only has my environmental variables because I read that the latest versions of Next.js and Now do not need any sort of configuration. Is there something I am missing? Here is my folder structure:

Folder structure

Most helpful comment

I fixed it, I was using Link component and Router.push from useRouter incorrectly, for push you have to:

Router.push('/post/[pid]', `/post/${id}`);

First parameter is the url which has to be exactly the path and name of the file and the second parameter is as which is the one where you pass the dynamic value.
https://nextjs.org/docs/api-reference/next/router#routerpush

For Link component it is similar, you have to:

<Link href="/post/[pid]" as={`/post/${id}`}>
  <a>First Post</a>
</Link>

href being the name of the file and as the one you pass the dynamic value.
https://nextjs.org/docs/api-reference/next/link#dynamic-routes

All 40 comments

I am having a very similar issue but with a server loading a static react app. I’ve followed every tutorial and put the recommended redirects in (including calling res.sendFile for app.get(“/“) to client, build, index.html) but I get the same pattern of dozens of 404s for pretty much everything much like in this screen shot.

Slight update in that by calling app.use(“client/build”), my server now finally loads my client build in localhost fine. (I must have gone through four tutorials that failed to mention that)

However, when I deploy it with npm run deploy, these kind of 404s still show.

I’m also experiencing 404s on dynamic/wildcard routes in production, but not when using now dev.

Repo and routes in question are viewable here.

(Some more context in this Twitter conversation with @leo)

@daneden same here. dynamic routes work locally with next start but not in production build.

@daneden same situation now dev seems to work... Using a monorepo, my now.json look like

{
  "version": 2,
  "public": false,
  "name": "XXXXXXX",
  "env": {
  },
  "builds": [
    { "src": "apps/web/next.config.js", "use": "@now/next" }
  ],
  "routes": [
    { "src": "/(.*)", "dest": "/apps/web/$1" }
  ]
}

And my exportPathMap +/- this:

const exportPathMap = async (defaultPathMap, { dev, dir, outDir, distDir, buildId }) => {
  const example = [{ slug: 'test1'' }, { slug: 'test2' }];
  const pages = example.reduce(
    (pages, agency) =>
      Object.assign({}, pages, {
        [`/test/${example.slug}/review`]: { page: '/test/[slug]/review' },
      }),
    {}
  );

  return Object.assign({}, pages, {
    '/': { page: '/' },
  });
};

Any suggestions ?

I'm having same issue with dynamic routing inside the api. It gives me a 404: NOT_FOUND error message. So for example I want to call

/ PASS
/page PASS
/api/test PASS

/[query] 404 NOT FOUND
/api/[id] 404 NOT FOUND

I didn't do anything on the code, it just stop working by it's own. When i push to application to ZEIT it works fine on LIVE, this only happend on "now dev"

@ivanhueso — I had the same issue as you. I had a little luck by running

now --prod --force

The -f or --force flag cleared my build cache (in production) and forced a production push. I'm guessing under the hood it reset my local cache too? Either way, it worked for me.

@sergioalen @belgattitude @CaptainChemist hey folks, I had a bit of correspondence with someone on the Zeit team over Twitter and came to a resolution. Not sure if the following steps will help you, but they solved my issues.

Part of the reason my routes were 404ing in prod is because they were using a combination of filesystem API routes and routes configs in now.json. These two things are typically supposed to be one-or-the-other: either you have API files like [parameter].js, or you send API requests to parameter.js with a passed parameter. Therefore the following changes worked for me:

  • Move api/path/[input].js to api/path.js
  • Update routes in now.json, so instead of dest being /api/path/$1 it becomes /api/path?input=$1
  • Destructure the parameter in the request

I have a commit here which demonstrates these changes.

None of these solutions work. I'm using a basic Link to a static page. Works in dev, but broken in production.

I'm in idiot. Fixed it.

Any newbies googling the problem, use HTTPS for your backend while developing. Was using HTTP and been getting 404/unexpected errors.

UPDATE: It only fixed the unexpected errors. Still getting 404 errors.
UPDATE2: I'm an idiot again. Files were in uppercase, Link hrefs were in lowercase. Fixed.

I have the same problem on dev, it seems that is trying to request the page from http://localhost:3000/_next/static/development/pages/ when you use the Link component to navigate but the url doesn't exist and then it automatically reloads and now it searches the page on http://localhost:3000 an that url exists so it loads correctly.
image

If you reload the page manually it works as well, so I think it has something to do with Link component taking you to a nonexistent url

I fixed it, I was using Link component and Router.push from useRouter incorrectly, for push you have to:

Router.push('/post/[pid]', `/post/${id}`);

First parameter is the url which has to be exactly the path and name of the file and the second parameter is as which is the one where you pass the dynamic value.
https://nextjs.org/docs/api-reference/next/router#routerpush

For Link component it is similar, you have to:

<Link href="/post/[pid]" as={`/post/${id}`}>
  <a>First Post</a>
</Link>

href being the name of the file and as the one you pass the dynamic value.
https://nextjs.org/docs/api-reference/next/link#dynamic-routes

@ferezoz Thank you for your solution. I searched a lot and try many ways but none of them solved the problem. Your solution is correct and standard.

When I directly want to open this page not working
https://lakebazar.com/grocery?category=petcare
but If I go sequentially , first lakebazar.com then /grocery then ?category=petcare it works. it is running next js production build (exported). I need help .

Edited & Added:
Yes. I have solved the problem. As many people trying to contact me via email. But
If you want to direct conversation, Please contact me via
Skype : https://join.skype.com/invite/qQ7UOkhy6gLJ
or
Telegram: https://t.me/ambition_cloud

Thanks.

@zinnah1995 Try updating your now CLI. I had the same issue in 17.1.1

Hi @LeonidasEsteban. Can you assist? 17.1.1 seems to be the latest release. What did you update to? I am getting 404's on every page, as if my now.json file isn't being registered.

To expand on @ferezoz 's note, and for anyone who is dealing with a route that has multiple params, don't forget to cover all [id] patterns:

push('/[id]/admin/spells/[spell_id]', `/${id}/admin/spells/${spell.id}`);

I see similar behavior as @zinnah1995 describes. If I go sequentially to e.g.: /something/[param] it works. When you hit reload (like F5) it gives you 404

Any update on that topic ?

@zinnah1995 @elvenking @d9cre if you are using next export before deploying your website it might be that your problem is that you are building the 404 pages at export time and then you are deploying those. And when you are going directly to a url is getting that 404 page because the static HTML is what is been returned on that first render, but if you go sequentially navigating to that url it is actually been rendered on client side and generated correctly.

I think you could check what is been rendered on your static HTML generated pages when doing the next export as a first step and if thats the case you can check for example whats happening in your getInitialProps, maybe you are trying to access req or res objects and that's giving undefined and returning and generating 404 page or maybe you are expecting a value to do a request to some service but is also giving an error and returning 404.

I am not sure but by what you are explaining that's what it seems to be happening. Hope it helps.

@ferezoz Thank you for reply. In my case, i am not even running next export. I have a 'serverless' app, run by ZEIT Now.

@ferezoz I'm currently running into the exact issue you are describing and seemingly the same issue as @zinnah1995. When running next start everything is working fine, however after next export my dynamic routes are only working _after_ client-side navigation, and I'm getting a 404 whenever those pages are the entry point to the app.

The docs for Static HTML Export suggest that dynamic routes should work as normal:

The exported app supports almost every feature of Next.js, including dynamic routes...

I've checked the rendered HTML and it seems to be fine. I'm not using getInitialProps, but am using dynamics imports via React.lazy (I've also tried with next/dynamic, setting the ssr option to false, but am having the same issue).

Any help would be really useful as I'm coming up short with a solution.

@neefrehman Hey, I just went into your repo and this is how you will fix it for your case:

You need to use exportPathMap.

The way next export works is by prerendering all pages to HTML; it does so based on a mapping called exportPathMap which offers a way to pre-define paths you will render as html.
https://nextjs.org/docs/advanced-features/static-html-export

You need to add this configuration in next.config.js like this:

Note: I went to your index.tsx and used your same logic to retrieve the array of sketch ids.

const fs = require("fs");
const path = require("path");

const withCSS = require("@zeit/next-css");

const getSketchArray = () => {
    const sketchArray = [];

    const sketchDirectory = path.join(process.cwd(), "src/sketches");
    const yearFolders = fs
        .readdirSync(sketchDirectory)
        .filter(folderName => folderName.length === 2);

    yearFolders.forEach(yearFolder => {
        const yearDirectory = path.join(
            process.cwd(),
            `src/sketches/${yearFolder}`
        );
        const monthFolders = fs
            .readdirSync(yearDirectory)
            .filter(folderName => folderName.length === 2);

        monthFolders.forEach(monthFolder => {
            const monthDirectory = path.join(
                process.cwd(),
                `src/sketches/${yearFolder}/${monthFolder}`
            );

            const sketches = fs
                .readdirSync(monthDirectory)
                .filter(sketchFileName => sketchFileName.length === 10);

            sketches.forEach(sketch => {
                const sketchId = sketch.substr(0, 6);
                const isValidSketchId = RegExp(/^[0-9]{6}$/).test(sketchId);

                if (isValidSketchId) sketchArray.push(sketchId);
            });
        });
    });

    return sketchArray.reverse();
};

module.exports = withCSS({
    async exportPathMap() {    // <---- Here it is the configuration I added
        let sketchsPages = {};

        getSketchArray().forEach(sketchId => {
            sketchsPages = {
                ...sketchsPages,
                [`/${sketchId}`]: { page: "/[sketch]" }
            };
        });

        return sketchsPages;
    },
    webpack(config) {
        ...
        return config;
    }
});

I did build, export and deploy and it worked.

Looks like an interesting project by the way, I wonder what are you building. 🙂

@ferezoz Thanks for this! Just copied it over and it did indeed work. Since the issue is a lack of an exportPathMap I thought I'd also go one step further and try using getStaticPaths in [sketch].tsx, since that should have the same result, and would let me get rid of some runtime js to extract query params. Unfortunately, I'm getting some other errors fixed: https://github.com/zeit/next.js/issues/12435#issuecomment-623643902.

It does seem a bit counterintuitive to build the page for each sketch, as the html is identical due to the content being dynamically imported, but I'm most definitely an edge case.

And thanks! I'm just making a site to play around with three.js, p5.js and WebGL in general.

I have the exact same issue as @zinnah1995 - All pages work fine if URL hit directly except the blog post. I can navigate to the posts perfectly fine but sharing the URL and loading it in a new tab gives 404.

I see similar behavior as @zinnah1995 describes. If I go sequentially to e.g.: /something/[param] it works. When you hit reload (like F5) it gives you 404

Any update on that topic ?

I have thesame issue with @elvenking

Hi! Same problem here @zinnah1995 , any update ?

@FrancoTanzarella @mayowadavid @elisegriset92 I had the exact issue (with next export), and what worked for me was setting up an exportPathMap, or using getStaticPaths in the dynamic routes.

exportPathMap and getStaticPaths does the trick because it builds an actual static file for each page on export but the problem still exists when I create new posts in my headless CMS, there are no static files generated for the new posts.

Update
In the docs here we can use a fallback to first show a loading screen while next generates the page in the background (or something in that line). I for some reason can't get this to work and page 404's now even when navigating to the page from a link that use to work.

@ferezoz Your solution worked perfectly. Thanks for the information.

@FrancoTanzarella @mayowadavid @elisegriset92 I had the exact issue (with next export), and what worked for me was setting up an exportPathMap, or using getStaticPaths in the dynamic routes.
@FrancoTanzarella @elisegriset92
Hi, I was able to fix the 404 page error on refresh by setting up server.js to load dynamic data on refresh. Also I remove all my stylesheet from index page and import everything in _app.js.
Everything is perfectly working now.

When I directly want to open this page not working
https://lakebazar.com/grocery?category=petcare
but If I go sequentially , first lakebazar.com then /grocery then ?category=petcare it works. it is running next js production build (exported). I need help .

Did you find a solution ??

When I directly want to open this page not working
https://lakebazar.com/grocery?category=petcare
but If I go sequentially , first lakebazar.com then /grocery then ?category=petcare it works. it is running next js production build (exported). I need help .

Did you find a solution ??

First of all you need to re-write your link as a clean url. I mean creating a clean url as lakebazar.com/grocery/category=petcare
Then proceed to configure your dynamic url in your server.js file with the clean url you have just created. The page will work fine on refresh or direct visit to the url. This work for me all the best. If you don't know how to configure clean url in server.js. I will suggest you search for tutorial on dynamic url. All the best.

Hi! Same problem here @zinnah1995 , any update ?

Yes. I have solved the problem. As many people trying to contact me via email. But I would like to prefer Skype or Telegram Chat, Please contact me via if you still facing problems
Skype : https://join.skype.com/invite/qQ7UOkhy6gLJ
or
Telegram: https://t.me/ambition_cloud

Thanks.
M. A. Zinnah
CEO
Ambition Cloud LLC

When I directly want to open this page not working
https://lakebazar.com/grocery?category=petcare
but If I go sequentially , first lakebazar.com then /grocery then ?category=petcare it works. it is running next js production build (exported). I need help .

Did you find a solution ??

Yes. I have solved the problem. As many people trying to contact me via email. But I would like to prefer Skype or Telegram Chat, Please contact me via if you still facing problems
Skype : https://join.skype.com/invite/qQ7UOkhy6gLJ
or
Telegram: https://t.me/ambition_cloud

Thanks.
M. A. Zinnah
CEO
Ambition Cloud LLC

I see similar behavior as @zinnah1995 describes. If I go sequentially to e.g.: /something/[param] it works. When you hit reload (like F5) it gives you 404

Any update on that topic ?

Yes. I have solved the problem.
If you want to direct conversation
Please Contact me via
Skype : https://join.skype.com/invite/qQ7UOkhy6gLJ
or
Telegram: https://t.me/ambition_cloud

When I directly want to open this page not working
https://lakebazar.com/grocery?category=petcare
but If I go sequentially , first lakebazar.com then /grocery then ?category=petcare it works. it is running next js production build (exported). I need help .

Edited & Added:
Yes. I have solved the problem. As many people trying to contact me via email. But
If you want to direct conversation, Please contact me via
Skype : https://join.skype.com/invite/qQ7UOkhy6gLJ
or
Telegram: https://t.me/ambition_cloud

Thanks.

it is solved for me by adding
exportTrailingSlash: true,
to next.config.js

Same issue here. Routing is not working correctly - 404 when navigating to routes from an external source (i.e. an email).

Per @ferezoz above (copied below), Link component needs href and as props.

Gotcha for me was that href value must match file system. For example: /store/[id].js you must use href="/store/[id]", where [id] is shared. The as prop can handle a dynamic value from a variable, like so:

as={`store/${someVariableWithID}`}

where someVariableWithID contains the store id.

Good:
<Link href="/store/[id]" as={`/stores/${store.id}`}>

Bad:
<Link href="/store/[store.id]" as={`/stores/${store.id}`}>

For Link component it is similar, you have to:

<Link href="/post/[pid]" as={`/post/${id}`}>
  <a>First Post</a>
</Link>

href being the name of the file and as the one you pass the dynamic value.
https://nextjs.org/docs/api-reference/next/link#dynamic-routes

To expand on @ferezoz and @tmikeschu:

If you have query parameters, you must also include them:

router.push(`/products/[variant]?sku=${product.product_id}`, `/products/edit?sku=${product.product_id}`);

@zinnah1995 do you mind posting your solution here for the rest of us that are having the same issue? thank you

I had the issue that after exporting and hosting the static site, refreshing on a dynamic page or directly opening it by url resulted in a 404 not found.

I resolved it by enabling trailing slashes, as described here: https://nextjs.org/docs/api-reference/next.config.js/trailing-slash
Hope this helps someone!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rgwozdz picture rgwozdz  ·  40Comments

remy picture remy  ·  42Comments

SteveALee picture SteveALee  ·  51Comments

vladejs picture vladejs  ·  36Comments

gyandeeps picture gyandeeps  ·  32Comments