"content not found" on direct page refresh/navigation in production
Environment
- Operating system : macos
- @nuxt/content: ^3.6.3
- nuxt ^4.0.3
- Node 24
In a Nuxt 4 project utilizing @nuxt/content, I am encountering an issue where content-rendered pages display "content not found" when directly navigating to the URL or refreshing the page with F5 in a production environment. The same pages load and render correctly when navigated via a <NuxtLink> from another page on the same site.
This issue is specific to production builds and is not reproducible in the local development environment. I am using @nuxt/content version ^3.6.3 and nuxt version ^4.0.3.
Version
v3
Reproduction
Reproducible Steps
-
Build the Nuxt project for production (npm run build).
-
Start the production server (npm run prod).
-
Navigate to a content-rendered page via an internal <NuxtLink>. The content loads correctly.
-
Perform a hard refresh (F5) on the same page. The page briefly shows the content before displaying a "content not found" message.
-
Open a new browser tab and paste the exact URL of the content page. The page loads with "content not found" immediately.
Description
-
The problem appears to be related to Server-Side Rendering (SSR) and how the client-side hydration process handles API requests for content. The initial server-rendered HTML seems to contain the content, but the subsequent client-side fetch fails.
-
The API endpoint
/api/_contentreturns a 404 error on page refresh or direct navigation. -
This behavior has also been reported in related GitHub discussions, such as nuxt/content#2378. But there has not been much discussion around this in long time and it has been open since about 2 years now so wondering if this issue still in discussion and planning to fix this. Hence creating this new issue.
Additional context
Adding reference to old GitHub issue: https://github.com/nuxt/content/issues/2378
Normal navigation works fine, but when I do a hard refresh (cmd+shift+r), then for a fraction of a second I see the content, then I see the message content not found. I am seeing this issue in production only, but unable to recreate it in the local dev environment.
Any workaround or suggestion would be really helpful.
Could you provide a reproduction repository or online on Stackblitz?
Is this happens on your production? From your description, I think this happens because your web-server/provider adds trailing slash to URLs and it misses.
If you are using queryCollection(COLLECTION).path(route.path) try to cleanup route.path
import { withoutTrailingSlash } from 'ufo'
queryCollection(COLLECTION).path(withoutTrailingSlash(route.path))
Could you also provide some information about your production environment? Where did you deploy? Did you use nuxt build or nuxt generate?
@farnabaz
Many thanks for the response. I have recreated the reproduction in Codesandbox: https://codesandbox.io/p/devbox/98ht6t
If you observe that when I access the /privacy or /imprint, it works, but for some reason accessing /privacy/ or /imprint/ not work.
I used the nuxt generate to build the .output, which we deploy. I believe your first response with withoutTrailingSlash should work i feel let me try this once.
@farnabaz
Many thanks again for the response. It seems to be working with your suggested changes:
import { withoutTrailingSlash } from 'ufo'
queryCollection(COLLECTION).path(withoutTrailingSlash(route.path))
I tried following in my code and its working:
import { withoutTrailingSlash } from 'ufo';
const fetchByPath = (path: string) =>
queryCollection(collectionName).where("path", "=", withoutTrailingSlash(path)).first();
But i am observing one small issue:
When I do npm run generate and run the code in preview mode using the npm run preview then during the hard refresh or opening in private mode i see that for a fraction of second i see content not found for some reason. How to avoid this? For example if you open this https://98ht6t-32781.csb.app/privacy/ and maybe refresh then you will see for a second content not found.
Example:
If you visit this page and refresh, you can see that flash for a fraction of a second:
https://98ht6t-32781.csb.app/privacy/
Reproduction
I’ve created a minimal reproduction here:
https://codesandbox.io/p/devbox/98ht6t
Question
Is this behaviour expected during hydration, or is there something in my setup I should fix to avoid the brief “content not found” state?
@farnabaz
When you get a chance, could you please take a look at this CodeSandbox example: https://codesandbox.io/p/devbox/98ht6t and suggest how to fix the issue?
I’ve noticed a small problem:
After running npm run generate and then serving the site with npm run preview, if I do a hard refresh or open the site in a private window, I briefly see a “Content not found” message before the correct content loads.
For example, if you open https://98ht6t-32781.csb.app/privacy/ and refresh, you should see this flash of “Content not found” for a second.
Is there a recommended way to avoid this?
Thanks @farnabaz for the solution! This fixed my issue as well.
I initially went down a rabbit hole thinking this was related to SQLite/WASM loading timing issues after checking out the network tab in the devtools. When I added a 2 to 10-second delay to the request, it worked fine, which reinforced my suspicion.
I ended up implementing a workaround with loading states, re-fetch logic, and exponential back-off, but this introduced an unwanted loading flash on every page refresh.
When I stumbled upon this thread, I was honestly skeptical that something as simple as a trailing slash could be the root cause. But after trying withoutTrailingSlash(route.path), it solved the issue completely.
The misleading error message really sent me down the wrong path. Hopefully this comment helps others who encounter the same issue and avoid the overly complex solutions I initially attempted!
I'm experiencing similar issues with github pages.
Seems fine when building locally and previewing it. But once deployed on github pages I get a brief flash of content not found. The console also shows hydration mismatch.
I am experiencing this issue. Build works locally and fails in production env as described above in Nuxt hub cloud flare worker deployments. My Nuxt config is set to drop trailing slashes with wrangler. I also trim the trailing slash as described above. Who ever can get this resolved I am willing to put a 100$ bounty on this being resolved as it is blocking my paying work.
Solved my issue so bounty is offline.
Issue traced to NuxtHub: I hadn’t enabled hub: { database: true } in nuxt.config.ts, so the database binding was missing—pure PEBKAC.
Thanks @farnabaz for the solution! This fixed my issue as well.
When I stumbled upon this thread, I was honestly skeptical that something as simple as a trailing slash could be the root cause. But after trying
withoutTrailingSlash(route.path), it solved the issue completely
I have the issue as well but it persists if i hardcode the path:
const { data: about } = await useAsyncData("about", () => {
return queryCollection("markdown").path("/data/about").first();
});
It of course only happens when i first enter the page, on navigation from another page it works perfectly fine.
What fixed it for me (but ugly)
const { data: about } = await useAsyncData("about", () => {
return queryCollection("markdown").path("/data/about").first();
}, {
server: false
});
I moved out of nuxt/content because of this bug. using server: false, just isnt a solution for SSR nuxt