next.js
next.js copied to clipboard
Next.js default not-found/404 page doesn't render on Vercel deployments
Link to the code that reproduces this issue
https://codesandbox.io/p/devbox/dry-dust-r83nds?file=%2Fnext.config.js%3A10%2C32
To Reproduce
- Start the application locally in dev.
- Navigate to a page that doesn't exist, i.e. http://localhost:3000/nosuchpage and see Next's default 404 page.
- Host the Next.js app on Vercel.
- Navigate to a page that doesn't exist, i.e. http://helloworld.com/nosuchpage and we see a broken version of the homepage rather than Next's not-found/404 page.
Current vs. Expected behavior
When navigating to incorrect/non-existent paths, the Next.js default not-found/404 page doesn't render on Vercel deployments, but does during local development.
We would expect to see the 404/not-found page in the Vercel's production deployment, just as we see it in dev.
Verify canary release
- [X] I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 23.1.0: Mon Oct 9 21:32:11 PDT 2023; root:xnu-10002.41.9~7/RELEASE_ARM64_T6030
Binaries:
Node: 21.3.0
npm: 10.2.4
Yarn: N/A
pnpm: N/A
Relevant Packages:
next: 14.0.5-canary.46
eslint-config-next: 14.0.3
react: 18.2.0
react-dom: 18.2.0
typescript: 5.3.2
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Not sure, App Router, Middleware / Edge (API routes, runtime), Routing (next/router, next/navigation, next/link)
Which stage(s) are affected? (Select all that apply)
Vercel (Deployed)
Additional context
We are hosting our Next.js app on Vercel.
As per these Next.js docs we have also tried making our own not-found.tsx component and placed it under ./app so all incorrect paths should result in the custom 404 being displayed, but they don't on Vercel, but do during local development. As suggested in other threads, we have also tried placing it throughout the application, but with no with success.
Note: running in production mode locally still gives a 404
@ericpesto I have thoroughly investigated the reported issue, and it appears to be related to deployment on Vercel rather than a 404 error. Upon closer inspection, I noticed that some files crucial for your project are missing, specifically those that you are attempting to import.
It seems that when you pushed the repository to GitHub, an empty folder structure may have been created. GitHub typically does not support an empty folder structure unless it contains at least one file. Consequently, when deploying this project on Vercel, an error arises due to the absence of necessary files.
To address this issue, I recommend ensuring that the repository on GitHub includes the required files within the folder structure before attempting the deployment on Vercel. This should resolve the error encountered during the deployment process. If you have any further questions or need assistance with this matter, please feel free to reach out.
My project is closed source and as such I can't provide the offending code/repo, building a like for like project in code sandbox to replicate the issue would take a fair bit of time.
On our end we have no problem deploying on Vercel, we can see the site live with no errors. The issue is that our 404 pages don't render for the site hosted on Vercel when incorrect urls paths are specified, whereas they do when running the project locally
Could this be related to:
https://github.com/vercel/next.js/issues/52765 https://github.com/vercel/next.js/issues/54239
None of the suggested 'work-arounds' fix the issue for me.
Project Settings / Change Framework preset from Other to Next.js Redeploy the project.
Our framework preset already is set to Next.js on the Vercel Dashboard
Add a custom 404 page this should fix the problem or an empty 404 page
We did try this, see above:
As per these Next.js docs we have also tried making our own not-found.tsx component and placed it under ./app so all incorrect paths should result in the custom 404 being displayed, but they don't on Vercel, but do during local development. As suggested in other threads, we have also tried placing it throughout the application, but with no with success.
I had a similar issue with App router only code. My workaround was to force 404 page based on the pathname:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// the following code is taken from: https://nextjs.org/docs/app/building-your-application/routing/middleware#setting-headers
export function middleware(request: NextRequest) {
const requestHeaders = new Headers(request.headers);
requestHeaders.set("x-pathname", request.nextUrl.pathname);
return NextResponse.next({
request: { headers: requestHeaders },
});
}
// the following code has been copied from https://nextjs.org/docs/app/building-your-application/routing/middleware#matching-paths
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
*/
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
}
// app/page.tsx
import { headers } from 'next/headers';
import { notFound } from "next/navigation";
export default async function Page() {
const pathname = headers().get("x-pathname");
if (pathname !== "/") return notFound();
return <>{/*... your page code */}</>
}
Any fix to this solution, having the same issue. I have not-found.tsx file in the app directory, works when run locally, but it never gets rendered in production for incorrect url?
Redeploying doesn't make the problem gone. But in development server, the 404 page is doing its work.
this worked for me
inside app create a file at [...not_found]/page.tsx
import {notFound} from "next/navigation"
export default function NotFoundCatchAll() {
notFound()
}
Reason: Since dynamic routes are resolved after static routes, we can solve it by creating a dynamic catch-all route using a [...not_found] folder and add it to our app folder.
This is still an issue for me as well.
I have app/not-found.js
, app/error.js
amd app/global-error.js
which work fine of dev, but after deployment on Vercel production I keep getting a very mixed experience:
- root/not_existing_link - returns default Next 500 page instead of my custom 404
- root/something_that_exists/not_existing_link - returns my custom 404 page as expected
I have only one dynamic route under app/[slug]. Adding aforementioned [...not-found] didn't help.
Any other suggestions?
I have the same issue. A dynamic route that is using generateStaticParams
will show the correct custom 404 page when a path does not exists. But when visiting other routes that not exists in the application the Vercel 404 page is shown.
I have one dynamic route in app/[post]/page.js
. 404's in this route shows the correct custom 404 page but other routes (for example /something/something-else
) shows the default Vercel 404.
I have the same issue. A dynamic route that is using
generateStaticParams
will show the correct custom 404 page when a path does not exists. But when visiting other routes that not exists in the application the Vercel 404 page is shown.I have one dynamic route in
app/[post]/page.js
. 404's in this route shows the correct custom 404 page but other routes (for example/something/something-else
) shows the default Vercel 404.
Good day,
If you want your not-found.js
page to catch all the 404's of your application, place that file in the root of app
directory.
Also, on prod deployment you may also want to add export const dynamicParams = false;
after the generateStaticParams
call in your [post]
segment route. That will tell next/vercel to render 404's instead of trying to find the non-existing page in the static routes and throw 500 error after not finding it.
Hope that helps! :)
Add a custom 404 page this should fix the problem or an empty 404 page
It is not solving the problem.
@eagrigorev
My file structure:
- app
- [post]
- page.js
- not-found.js
- [post]
Good day, If you want your
not-found.js
page to catch all the 404's of your application, place that file in the root ofapp
directory.
I have a not-found.js
in the app directory but this is only shown on "defined routes" such as [post]
. On other routes (such as /something/something-else) a Vercel 404 is shown.
Also, on prod deployment you may also want to add
export const dynamicParams = false;
after thegenerateStaticParams
call in your[post]
segment route. That will tell next/vercel to render 404's instead of trying to find the non-existing page in the static routes and throw 500 error after not finding it.
This does not matter. If someone is getting 500 error here it probably something else. Maybe generateMetadata
function. For me it's fine to try generating pages that did not exists while building.
@lejtzen
I have the same structure, and it works fine for me, every route, even something/something/something-else is getting tracked by not-found.js
. Maybe we have some other differences in the code? In my [post]
page I explicitly check condition when nothing found in defined routes and return notFould()
. I also have export const dynamicParams = false;
in the end of the file.
You can check my [post] page.js here and compare it to yours: https://github.com/eagrigorev/eagrigorev-website/blob/master/src/app/%5Bslug%5D/page.js
Hope that will help :)
not-found
page in root directory (app) works fine, but the issue occurs in dynamic route.
- app
- profile
- [id]
- page
- error
- layout
- not-found
- [id]
- not-found
- profile
Inside page
I'm fetching user by id. If user has not been found fetch function throws error, then error
page catches this error and returning notFound()
page.tsx
export default async function ProfilePage({ params }: ProfilePageProps) {
const userId = validateId(params.id)
const token = await getServerToken()
if (!token) redirect('/')
const { profile } = await getUser(token, { userId })
return (
<ProfileCard {...profile}>
<Playback />
</ProfileCard>
)
}
error.tsx
export default function ProfileError({ error, reset }: ErrorProps) {
if (error.message === 'The access token expired') reset()
if (
error instanceof Error &&
[VALIDATION_FAILED_UUID_EXPECTED, USER_NOT_FOUND].includes(error.message)
)
return notFound()
console.error(error)
}
Everything works on development, the issue occurs on production. Not found page is not rendered, instead I'm getting console errors.
Error: An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.
Error: invariant expected app router to be mounted
Error: Minified React error #419; visit https://react.dev/errors/419 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.