Caching issue with Next.js App Router - Vercel Deployment

Dear Prismic team

I set up a new Next.js App Router project using your setup command npx @slicemachine/init@latest and walking trough your step by step setup guide.

In previous versions, I never had issues deploying the site to Vercel and setting up Prismic Webhooks to trigger redeploys.

With this new project it seems like there are some caching issues with Vercel:
If I push a new commit to Github or if I edit content on Prismic, it triggers a new deploy correctly.
Unfortunately those deploys are missing the newest contents from Prismic and every then and now it appears the following error:

ForbiddenError: Access to this Ref requires an access token
    at Client.fetch (/vercel/path0/.next/server/chunks/734.js:2367:27)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Client.get (/vercel/path0/.next/server/chunks/734.js:1450:16)
    at async Client.dangerouslyGetAll (/vercel/path0/.next/server/chunks/734.js:1515:28)
    at async Client.getAllByType (/vercel/path0/.next/server/chunks/734.js:1767:16)
    at async Object.generateStaticParams (/vercel/path0/.next/server/app/portfolio/[portfolio]/[uid]/page.js:536:19)
    at async buildParams (/vercel/path0/node_modules/next/dist/build/utils.js:917:36)
    at async /vercel/path0/node_modules/next/dist/build/utils.js:934:33
    at async /vercel/path0/node_modules/next/dist/build/utils.js:1067:117
    at async Span.traceAsyncFn (/vercel/path0/node_modules/next/dist/trace/trace.js:103:20) {
  url: 'https://my-repo.cdn.prismic.io/api/v2/documents/search?q=%5B%5Bat%28document.type%2C+%22project%22%29%5D%5D&pageSize=100&ref=ZLphbxEAACMAGdpk&routes=%5B%7B%22type%22%3A%22page%22%2C%22uid%22%3A%22home%22%2C%22path%22%3A%22%2F%22%7D%2C%7B%22type%22%3A%22page%22%2C%22path%22%3A%22%2F%3Auid%22%7D%2C%7B%22type%22%3A%22portfolio%22%2C%22path%22%3A%22%2Fportfolio%2F%3Auid%22%7D%2C%7B%22type%22%3A%22project%22%2C%22resolvers%22%3A%7B%22portfolio%22%3A%22portfolio%22%7D%2C%22path%22%3A%22%2Fportfolio%2F%3Aportfolio%2F%3Auid%22%7D%5D',
  response: {
    type: 'api_security_error',
    message: 'Access to this Ref requires an access token',
    oauth_initiate: 'https://my-repo.prismic.io/auth',
    oauth_token: 'https://my-repo.prismic.io/auth/token'
  }
}

In both cases I have to redeploy the site manually and force Vercel to not use the cache. If I do so, everything works fine.

Do you have any idea of how I can fix this?

In my prismicio.ts file I have the following recommended code which contains some lines about caching:

export const createClient = (config: prismicNext.CreateClientConfig = {}) => {
  const client = prismic.createClient(repositoryName, {
    routes,
    fetchOptions:
      process.env.NODE_ENV === 'production'
        ? { next: { tags: ['prismic'] }, cache: 'force-cache' }
        : { next: { revalidate: 5 } },
    ...config,
  });

  prismicNext.enableAutoPreviews({
    client,
    previewData: config.previewData,
    req: config.req,
  });

  return client;
};

Thanks for your support.

I ran into the same issue. Adding an access token solved it. More info on generating one can be found here: Access Token - Documentation - Prismic

  const client = prismic.createClient(repositoryName, {
    routes,
    accessToken: process.env.PRISMIC_ACCESS_TOKEN,
    fetchOptions:
      process.env.NODE_ENV === "production"
        ? { next: { tags: ["prismic"] }, cache: "force-cache" }
        : { next: { revalidate: 5 } },
    ...config,
  });

In your .env.local and on Vercel add:
PRISMIC_ACCESS_TOKEN=YOUR_TOKEN

1 Like

Thanks for your answer.
Does this solve the content caching issue as well?

I was also having caching issues but realized that was my fault. I had set dynamicParams to false. Which I had done in my page.tsx:

export const dynamicParams = false;

Removing it solved that issue for me. You can read more about dynamicParams here: File Conventions: Route Segment Config | Next.js

I also use export const dynamicParams = false; in my page files.
But I guess, this makes sense as my pages only update when there is an update in the Prismic Repo - and if this is the case, it triggers a redeploy with a webhook.

If I understand it correctly, the dynamicParams setting only impacts routes and not content on those pages, and currently I have the issue that new routes and new contents (like a list of entities of a custom type) are missing out of builds.

dynamicParams = false is also included in the Page Snippet (in Slicemachine), so I guess this complies with the core Prismic concept?

I reconfigured the webhook from vercel to prismic and it is now working as expected.

1 Like

So I guess that adding the accessToken and re-doing the webhook solved my problem. I hope that this can help you guys

1 Like

I've gone down a similar rabbit hole here, and found a decent solution with Vercel.

The new prismic/next/isr fetch() cache setup was working great; updates in Prismic were invalidaiting the Vercel correctly via the /api/revalidate call.

However, at build time I was getting "repo not found" errors from the prismic API. The build routine was trying to query an old cached master ref.

I found that because Vercel stores the whole .next build directory between builds, Next was using fetch responses from the previous build under ./next/cache/fetch-cache.

Nuke that directory before each build, and the latest Prismic master will be used. No need to mess with createClient() setup.

"scripts": {
    "build": "rm -rf .next/cache/fetch-cache && next build",
},

I hope this helps somebody out there! - Kyle

7 Likes

This was helpful. We had a similar situation. When there is multiple [:uid]/page.js files, e.g. /[:uid]/page.js and /some-path/[:uid]/page.js

It seems like subsequent createClient() calls trigger a not-found repo error. There very well be some kind of fetch cache on createClient() or client.getAllByType(...).

After adding Kyle's suggestion:

  • client.getByType('page')
  • client.getAllByType('page')
  • as well as creating a static array of uid's

All work as expected within generateStaticParams()

It probably stems from the changes in fetch with next.js 13.x and the app router. All fetch requests get cached by default (it think).

1 Like

Another option is to use the Environment Variable VERCEL_FORCE_NO_BUILD_CACHE with a value of 1. You can find limited info on that here. This has solved the issue for me on multiple projects.

Edit: After another day of dev the error RefExpiredError: The provided ref is no longer accessible, it has expired. has popped back up using the VERCEL_FORCE_NO_BUILD_CACHE option shared above. I'm going to give @kyle's suggestion a shoot, hopefully with better luck.

1 Like

Perhaps it would be helpful, if you could extend the Next.js / Deploy documentation with the most proven deployment methods (in addition to the blog post).
Especially for those who are new to Prismic and the App Router, it might be difficult to find the best way to deploy the projects.

I now use on-demand revalidation with a webook to /api/revalidate to reflect quick changes, but still trigger a rebuild of the application to rebuild my sitemap (app/sitemap.js) too.
If anyone has a better approach to that, please let me know. :slightly_smiling_face:

1 Like

Hey everyone,

We've opened an issue on the Next.js GitHub repository. Please feel free to upvote this issue and follow along for updates:

Sam

2 Likes

I'm now also facing caching issues on Vercel in Next.js applications (v14.0.3) using the pages router.
Editing content in Prismic triggers a complete rebuild but the new contents are missing.

This also happens with the following suggested option:

Hello everyone!

I wanted to join the conversation as I built the Prismic website using Next.js.

I've encountered similar issues as all of you have reported after migrating to app router. I've tried various solutions over the past few months.

However, since version 14.0.2, we haven't experienced any problems with revalidateTag() not revalidating.

The only unconventional setup we still have in place is VERCEL_FORCE_NO_BUILD_CACHE=1. As Nathan mentioned earlier, this is used to opt out of Vercel's build cache. We use it because when we trigger deploys from code changes in Git, we sometimes get outdated content if we've made content changes since the last build. It's not ideal since it doubles the build time, but now that revalidateTag() is working, our site doesn't need to rebuild as often.

Since version 14.0.4 has been released, it's possible that this issue has been fixed, as the update promises to resolve many caching issues. We're currently on the latest version, but we haven't had the chance to remove VERCEL_FORCE_NO_BUILD_CACHE=1 and test it yet.

Samuel

I have updated to version 14.0.4, and the cache issues have disappeared

2 Likes

That's wonderful news! Thank you for letting us know. :pray:

Did you disable the build cache with VERCEL_FORCE_NO_BUILD_CACHE=1 earlier because of deploying outdated caches? If so, have you attempted to remove it as well?

Samuel

No, I did not use VERCEL_FORCE_NO_BUILD_CACHE

This is still not working in Next 14.0.4 for me. I have a simple Server Component page with export const revalidate = 120; And the data fails to refresh after build. I am seeing error logs with F [Error]: Ref not found. Ensure you have the correct ref and try again. Master ref is: ZXjLpxEAACIAKO1b
at N.fetch (/var/task/apps/web/.next/server/chunks/156.js:1:12940)...

1 Like

I was able to solve the "[Error]: Ref not found." issue by using an access token.