Next.js: Using `getStaticPaths` in combination with `trailingSlash: true` leads to invalid json prefetching

Created on 12 Oct 2020  路  6Comments  路  Source: vercel/next.js

Bug report

Using getStaticPaths in combination with trailingSlash: true leads to invalid json prefetching. For a link to a dynamic route, the json file that is prefetched includes an invalid slash in the path, causing a 404 to be returned. However, when clicking the link and landing on the dynamic page the correct json file is fetched.

To Reproduce

  1. Configure
// next.config.js
module.exports = {
  trailingSlash: true,
};
  1. Add dynamic route
// pages/[name].js
export default function Hello({ name }) {
  return <div>Hello {name}</div>
}

export function getStaticProps(context) {
  return {
    props: {
      name: context.params.name
    }
  };
}

export function getStaticPaths() {
  return {
    paths: [
      { params: { name: 'world' } }
    ],
    fallback: false
  };
}
  1. Add link to dynamic route
// pages/index.js
import Link from 'next/link'
export default function Home() {
  return (
    <div>
      <Link as="/world" href="/[name]">
        <a>Hello world</a>
      </Link>
    </div>
  )
}
  1. Export using next build && next export
  2. Open root page
  3. Observe a network request for https://example.com/_next/data/some-hash/world/.json returning a 404

Expected behavior

The correct https://example.com/_next/data/some-hash/world.json is (pre)fetched

System information

  • OS: macOs
  • Browser (if applies): chrome
  • Version of Next.js: 9.5.5
  • Version of Node.js: v12.18.0
good first issue bug

Most helpful comment

I have exactly the same issue, any updates?

All 6 comments

I've had a little look at this (it's also breaking the prefetching in the app I'm currently working on), I have pushed a little demo app here to reproduce the issue.

That app is now versioned to 9.5.4-canary.4, the earliest version where I see it happening, 9.5.3-canary.3 or earlier it seems fine, so I'm guessing it's related to this commit 489cad36bcc95f93ce012712369a83809e91956d that was introduced between those two versions.

Adding a little debugging, before this commit, the function _resolveHref was returning

{
  href: "/[name]/"
  pathname: "/[name]"
  ...
}

but after it returns:

{
  href: "/[name]/"
  pathname: "/[name]/"
}

and further along gets translated to '/world/' and then has the extension appended to it, creating '/world/.json'.

Just as a test, I've tried sanitising the URL just before calling prefetchData, it seems to resolve this issue, but not so confident it doesn't introduce others

git diff
diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts
index 85921f4d6..268b86920 100644
--- a/packages/next/next-server/lib/router/router.ts
+++ b/packages/next/next-server/lib/router/router.ts
@@ -1146,6 +1146,8 @@ export default class Router implements BaseRouter {
     }

     const route = removePathTrailingSlash(pathname)
+    url = removePathTrailingSlash(url)
+
     await Promise.all([
       this.pageLoader.prefetchData(
         url,

I have exactly the same issue, any updates?

Following on this. It is a really serious issue for our project, as not being able to fetch the pages .json breaks prefetching of links, causing the entire app to re-render when you click on a link and subsequent loss of data in React contexts.

As a temporary workaround, maybe just turn it off with prefetch={false} on the affected Links.

What worked for me is disabling prefetch in my Links and prefetching with router.prefetch in a Hook instead:

function LinkWrapper({ slug, text }) {
  const router = useRouter();

  useEffect(() => {
    router.prefetch(`/posts/${encodeURIComponent(slug)}`);
  }, []);

  return (
    <Link href={`/posts/${encodeURIComponent(slug)}/`} prefetch={false}>
      <a>{text}</a>
    </Link>
  );
}

+1 I am also running into issues with this.

Was this page helpful?
0 / 5 - 0 ratings