404 Error in Category Menu in Sanity + Next.js

3 replies
Last updated: Jul 18, 2021
Sorry again, I'm still struggling with a category menu in a Sanity + Next.js project. I've been trying to add a
pages/[slug].js
file to display posts only in a selected category but anything I've tried resulted in errors (most notable one being a cors error – I probably did something wrong there). I've tried to reproduce an error and the simplest version I could come up with is cloning the
vercel/next.js
example and copying the
pages/posts/[slug].js
's contents into the
[slug].js
(and adjusting the import paths). In this case I get a 404 error while the
pages/posts/[slug].js
works properly. Is this example supposed to work or is it that I don't know something really obvious (I'm fairly new to both Sanity and Next)?
AI Update

Based on your description, you're running into a common Next.js routing issue when working with Sanity. The problem is likely that when you create a top-level pages/[slug].js file by copying from pages/posts/[slug].js, the GROQ queries are still configured for the nested route structure and aren't returning the correct data for your category pages.

Here's what's probably happening:

The 404 Error: When you copied the code from pages/posts/[slug].js to pages/[slug].js, the getStaticPaths function is still querying for posts with slugs, but your top-level route needs different logic. Next.js returns a 404 when getStaticPaths doesn't return the slug you're trying to access, or when getStaticProps can't find the content for that path.

Common fixes:

  1. Update your GROQ query in getStaticPaths to fetch the right content type. If you want to show category pages at the root level, your query should look for categories instead of posts:
export async function getStaticPaths() {
  const paths = await client.fetch(
    `*[_type == "category" && defined(slug.current)][].slug.current`
  );

  return {
    paths: paths.map((slug) => ({ params: { slug } })),
    fallback: true, // or 'blocking'
  };
}
  1. Update getStaticProps to fetch the category and its associated posts:
export async function getStaticProps({ params }) {
  const { slug } = params;
  
  const category = await client.fetch(
    `*[_type == "category" && slug.current == $slug][0]`,
    { slug }
  );
  
  const posts = await client.fetch(
    `*[_type == "post" && references(*[_type == "category" && slug.current == $slug]._id)]`,
    { slug }
  );

  return {
    props: {
      category,
      posts,
    },
    revalidate: 60,
  };
}

About the CORS error: This usually happens when you're trying to call the Sanity API from the client-side (like in a React component) without proper configuration. Always fetch Sanity data in getStaticProps, getServerSideProps, or API routes—never directly in components during client-side rendering. The Vercel with-sanity example does this correctly by keeping all Sanity queries in Next.js data fetching functions.

Why pages/posts/[slug].js works but pages/[slug].js doesn't: The nested route works because its queries are specifically configured for that route structure. When you copy it to the root level without adjusting the queries, it's looking for content that may not exist at those paths, or the query results don't match what the root-level route expects.

The misplaced comma issue you mentioned in the original thread is actually quite common! JavaScript syntax errors in getStaticPaths or getStaticProps can cause cryptic errors that manifest as 404s or CORS issues.

The key takeaway: make sure your getStaticPaths returns the slugs that actually exist for your category content type, and getStaticProps fetches the right data for those slugs. The queries need to match your schema and the route structure you're building.

can you reproduce in codesandbox or stackblitz?
HI - I'm not a next.js user, but I would imagine that the
pages/[slug]
route is expecting to present data from a single
page
. Is the next app working on its own? Is your query working on its own? If you include links to code or paste in the parts you are working on someone will take a look!
Thank you for replying, I've figured it out by now. …It was a misplaced comma that was causing weird errors 🤦

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?