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

404 errors with dynamic routes in next.js and now #3294

Open
CaptainChemist opened this issue Nov 11, 2019 · 68 comments
Open

404 errors with dynamic routes in next.js and now #3294

CaptainChemist opened this issue Nov 11, 2019 · 68 comments

Comments

@CaptainChemist
Copy link

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

@SavedByZero
Copy link

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.

@daneden
Copy link

daneden commented Dec 18, 2019

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)

@sergioalen
Copy link

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

@belgattitude
Copy link

@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 ?

@ivanhueso
Copy link

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"

@carsonjones
Copy link

@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.

@daneden
Copy link

daneden commented Jan 3, 2020

@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.

@nick-tw
Copy link

nick-tw commented Feb 21, 2020

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

@nick-tw
Copy link

nick-tw commented Feb 23, 2020

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.

@Ferezoz
Copy link

Ferezoz commented Feb 27, 2020

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

@Ferezoz
Copy link

Ferezoz commented Feb 28, 2020

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

@alihesari
Copy link

@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.

@zinnah1995
Copy link

zinnah1995 commented Mar 29, 2020

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.

@LeonidasEsteban
Copy link

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

@d9cre
Copy link

d9cre commented Apr 4, 2020

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.

JiangWeixian added a commit to JiangWeixian/cheatsheets that referenced this issue Apr 12, 2020
@tmikeschu
Copy link

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}`);

@elvenking
Copy link

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 ?

@Ferezoz
Copy link

Ferezoz commented Apr 24, 2020

@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.

@elvenking
Copy link

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

@neefrehman
Copy link

@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.

@Ferezoz
Copy link

Ferezoz commented May 4, 2020

@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. 🙂

@neefrehman
Copy link

neefrehman commented May 4, 2020

@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: vercel/next.js#12435 (comment).

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.

@ghost
Copy link

ghost commented May 6, 2020

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.

@mayowadavid
Copy link

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

@elisegriset92
Copy link

Hi! Same problem here @zinnah1995 , any update ?

@neefrehman
Copy link

@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.

@paulbreslin
Copy link

paulbreslin commented Dec 5, 2020

Just came across this, my issue was that I had a folder named posts[id]. When the actual structure needed to be as follows:

Screenshot 2020-12-05 at 13 20 31

I think people are getting caught out by this because the GitHub UI for the Dynamic Routes example makes it looks like a single folder should be called post[id]

Screenshot 2020-12-05 at 13 21 49

@smitbarmase
Copy link

I solved the problem. 😄

Problem: I was not able to route directing to the "dynamic" path in production, it was showing 404 Not Found. Using "yarn dev" was working fine. After build, it was not working as expected.

Solution: So the problem was building the static site. I'm sure you must not be using "getStaticProps" and "getStaticPaths" in your dynamic page. You should add both of them so that while building Next will build your dynamic path into static pages.

export async function getStaticProps(context) {
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  if (!data) {
    return {
      notFound: true,
    }
  }

  return {
    props: {}, // will be passed to the page component as props
  }
}

and

// This function gets called at build time
export async function getStaticPaths() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => `/posts/${post.id}`)

  // We'll pre-render only these paths at build time.
  // { fallback: false } means other routes should 404.
  return { paths, fallback: false }
}

Official documentation: https://nextjs.org/docs/basic-features/pages#static-generation-with-data

@tesshsu
Copy link

tesshsu commented Dec 16, 2020

HI,
What about static page ? If I just copy URL then run on the browser it will show "not found"
Here is process:

  • npm run build
  • ce out
  • deploy to server
  • click one menu of homepage, for example https://domain/about
  • then copy this url
  • show " page Not Found

The requested document was not found on this server.

It seems to me the router could not be reconginze once deploye to build

Does this also has to apply "getStaticProps" and "getStaticPaths" ?

Or it could be just add some configuration in nex.config file ?

tks

@m9rc1n
Copy link

m9rc1n commented Dec 25, 2020

I got similar problem.
It got solved by changing deployment service from Netlify to Vercel. Maybe Netlify isn't supporting SSG out of the box?

I followed https://github.com/vercel/next.js/tree/canary/examples/dynamic-routing to set up my deployment.

@daveteu
Copy link

daveteu commented Jan 7, 2021

In static site, dynamic urls works in the app e.g. /dashboard/customer/12345/, however it doesn't work when you use /dashboard/customer/12345/ directly. Refreshing will also cause a 404 error.

Error seems to occur because there isn't a index.js entry point like how we handle a create react app.

It has nothing got to do with router.query parameter because JS and CSS files etc were totally not loaded when you attempt to load the url directly, or refreshing.

@smitbarmase
Copy link

@tesshsu Did you fixed it? I solved it using "getStaticProps" and "getStaticPaths", and was able to get correct page while directly routing to that URL in production.

@daveteu
Copy link

daveteu commented Jan 18, 2021

I end up just using Vercel, because they use npm run start. I guess NextJS need npm run start in order for their routing to run.

@vbilltran68
Copy link

@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 you navigate to it okay, if you reload the page => 404 error will occur

@vbilltran68
Copy link

vbilltran68 commented Mar 1, 2021

@tesshsu Did you fixed it? I solved it using "getStaticProps" and "getStaticPaths", and was able to get correct page while directly routing to that URL in production.

with newly created product / post / item. what happened to the static files/static paths? (need to waiting for next builds ?)

@WorarojS
Copy link

WorarojS commented Mar 10, 2021

well i just got some trick, the issue isnt from nextjs but your server. in my case i was deploying it on apache server so i add .htaccess to redirect 404 page to index.js. it's not an exactly solution but it could help someone to get over this 2 years old issue.

@ZephyrBlu
Copy link

I was also experiencing this 404 issue and it was extremely frustrating. I managed to hack together a solution that solves the problem though.

I wrote a hacky script which extracts top-level HTML files from the out directory, renames them without the .html extension and then copies them to bucket storage with Content-Type=text/html (This makes the bucket serve them with pretty URLs. I.e. no .html extension). Generated CSS files are also copied.

The caveats are that you can't use any JS and you have to specify hrefs in your <a> tags instead of <Link> tags, but it works like a charm. You can navigate directly to routes and view the static HTML page and navigate through pages without JS.

The script is specific to my setup and the gsutil command line tool, but I think it should be quite easy to alter it to fit your needs.

I have the script in a gist, but I'll paste the whole thing here to ensure there's no possibility of a dead link.

Note: This requires Node ~12 or something for recursive directory creation

(async () => {
    const fs = require('fs').promises;
    const { execSync } = require('child_process');
    const CSS_PATH = '_next/static/css';
    const OUTPUT_DIR = 'deploy';
    const BUCKET = 'qnt.gg';

    const generatedFiles = await fs.readdir('out');
    const staticHtmlFiles = generatedFiles.filter((name) => (
        name.slice(-5) === '.html' && name !== '404.html'
    ));

    const createDir = async (dir) => {
        try {
            await fs.access(dir);
            await fs.rmdir(dir, { recursive: true });
        } catch {
            // do nothing
        }
        await fs.mkdir(dir, { recursive: true });
    };

    await createDir(OUTPUT_DIR);

    Promise.all(staticHtmlFiles.map(async (name) => {
        const noExt = name === 'index.html' ? name : name.slice(0, -5);
        const file = await fs.readFile(`out/${name}`);
        await fs.writeFile(`${OUTPUT_DIR}/${noExt}`, file);
    })).then(async () => {
        const deployFiles = await fs.readdir(OUTPUT_DIR);
        console.log('Deploying files:', deployFiles);

        console.log('\nChecking bucket');
        const bucketFiles = execSync(`gsutil ls gs://${BUCKET}`).toString();
        console.log('Found:', bucketFiles);
        if (bucketFiles) {
            console.log('Deleting files');
            execSync(`gsutil rm -r gs://${BUCKET}/*`);
        }

        console.log('\nUploading files');
        execSync(`gsutil -h "Content-Type:text/html" cp ${OUTPUT_DIR}/* gs://${BUCKET}`)
    }).then(async () => {
        await createDir(`${OUTPUT_DIR}/${CSS_PATH}`);
        const staticCssFiles = await fs.readdir(`out/${CSS_PATH}`);

        Promise.all(staticCssFiles.map(async (name) => {
            const file = await fs.readFile(`out/${CSS_PATH}/${name}`);
            await fs.writeFile(`${OUTPUT_DIR}/${CSS_PATH}/${name}`, file);
        })).then(async () => {
            const deployFiles = await fs.readdir(`${OUTPUT_DIR}/${CSS_PATH}`);
            console.log('Deploying files:', deployFiles);
            console.log('\nUploading files');
            execSync(`gsutil cp ${OUTPUT_DIR}/${CSS_PATH}/*.css gs://${BUCKET}/${CSS_PATH}/`)
        });
    });
})();

@dethstrobe
Copy link

dethstrobe commented Apr 11, 2021

I'm having a similar issue where my dynamic routes in my webapp are getting 404s when I refresh the page. But only on vercel. Locally it works as expected.

The app: https://oma3.vercel.app/
The repo: https://github.com/HeyOmae/OMA3/tree/main

The dynamic pages are populated with data from indexedDB which will be unique to every user. So I don't think I can really use static props. Is there anyway to make NextJS behave more like a SPA on vercel?

I also created a discussion on NextJS which has seen no traction.

@matiasfacio
Copy link

matiasfacio commented May 4, 2021

Hi everyone,
I'm getting a 502 error when trying to access the dynamic paths (only in production mode in Netlify). I don't get an 404 error but an error message saying that the Task timed out after 10.01 seconds.
I rewrite the Link as someone wrote above, but that didn't solve my problem.
Anyhelp appreciated!!

EDIT: I just deployed the app in Heroku and it just worked very well, no issues anymore.

@anand9746
Copy link

hi,
My dynamic link in next js are working in the local host . but it is not working in dev & production side...when page is refresh or paste the link some where else... i dont knw to do iam so confussed .. is their anybody knw what the real problem is?

@joshkay
Copy link

joshkay commented May 24, 2021

I am also running into this issue. Works just fine when built and run locally, but on vercel I am getting a 404 error.

@rheng001
Copy link

Running into same issue

@Jrodseth
Copy link

Jrodseth commented Jun 2, 2021

For those working with dynamic routes and deploying a static export to vercel, github pages, etc:

You need to map dynamic request paths to your dynamic page destination using the exportPathMap config option in your next.config file.

An example assuming a /dynamic/[routeId] page:

module.exports = {
  exportPathMap: async function ( ) {
    return {
      '/dynamic/route-a': { page: '/dynamic/[routeId]' },
      '/dynamic/route-b': { page: '/dynamic/[routeId]' },
    }
  },
}

@amsalimsema
Copy link

amsalimsema commented Jun 9, 2021

The nextjs starter from vercel throws an error with 'npm run dev'

Capture

Any quick fix?

@bpred754
Copy link

Not sure if this belongs here, but I thought I would share since I don't see any documentation for it. Dynamic routes cannot have dashes - in the names. Dashes in dynamic routes work locally, but I kept on getting 404s when deploying with serverless-nextjs to AWS CloudFront.

pages/[foo-bar]/index.tsx // Causes 404s in production

pages/[foobar]/index.tsx // Valid

Hope this saves someone the pain I went through to diagnose this!

@sanglt1902
Copy link

I have the same issue with this but my solution is just to change the src value

Screen Shot 2021-10-03 at 00 22 39

Screen Shot 2021-10-03 at 00 21 10

form
 <script src="js/jquery.min.js"></script>

to

 <script src="/js/jquery.min.js"></script>

@curlyz
Copy link

curlyz commented Nov 6, 2021

Make sure the framework preset is NextJS. Mine was something triangle and then only export 2 file in the build output.
Took me 1 hour luckily.

image

@je0ngyun
Copy link

I also had a similar issue with dynamic routing inside the api.
In my case, dynamic routing worked well in dev mode and local production mode after build, but it did not work when deployed to Vercel.

├── api
├── package.json
├── pages
│   ├── _app.page.tsx
│   ├── api
│   │   ├── index.api.ts
│   │   ├── oauth

The folder structure at the time of the problem was as above, and it was solved by renaming the duplicate api folder and distributing it.

@CVarisco
Copy link

Hi! I'm experiencing this issue where local dev and production building on local works fine.

This is the folder structure.
Screenshot 2022-12-13 at 15 40 10

I'm trying to have an API Catch all route used as a proxy. But I'm getting 404 when I try to call the proxy in a cloud environment.

Next.js version 13.0.6

Example:

POST /api/proxy/user/signup 404
GET /api/healthz 200

@avin1208
Copy link

avin1208 commented Feb 1, 2023

@CVarisco just import
module.exports = {
trailingSlash: true,
}

in next.config.js file

@dm03514
Copy link

dm03514 commented Feb 3, 2023

Hello Everyone! I"m seeing the same issue. I am building and exporting my site and deploying on cloudflare pages. As mentioned earlier in this thread, I believe that it is because i have a dynamic route and that route is getting rendered to a 404.

I believe that this is most in line with my problem, cross posting here:

vercel/next.js#32375 (comment)

@avin1208
Copy link

avin1208 commented Mar 7, 2023

@dm03514 have you use
module.exports = {
trailingSlash: true,
}

this solution ?

@praveenydv
Copy link

praveenydv commented Apr 17, 2023

I solved it. At the root of my app, I routed to same URL again on frontend side. So add this code in your _app.tsx file.

  useEffect(() => {
    router.push(router.asPath)
  },[])```

@fwextensions
Copy link

fwextensions commented Jun 7, 2023

Make sure the framework preset is NextJS. Mine was something triangle and then only export 2 file in the build output. Took me 1 hour luckily.

👆@curlyz solved it for me. I thought I had started from a Next.js template, so I have no idea why the framework in settings was △ Other. The deployment summary did indeed show that just the favicon was getting deployed, but I couldn't figure out why.

image

Changing the framework to Next.js fixed it immediately, and correctly deployed all the built files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests