Fix Error: Error: Custom 404 page could not be rendered. pages/404.tsx has an error. in Next.js
This error occurs when your custom 404 page has a runtime or build-time error, causing Next.js to fail when rendering the not-found page. Common causes include importing server-only modules, using hooks incorrectly, or having syntax errors. Fix it by ensuring the 404 page is a simple static component with no data-fetching methods.
Reading the Stack Trace
Here's what each line means:
- at renderToHTML (/app/node_modules/next/dist/server/render.js:902:15): The server-side rendering of the 404 page failed, preventing Next.js from showing the custom not-found page.
- at async DevServer.render404 (/app/node_modules/next/dist/server/base-server.js:1472:25): Next.js attempted to render the custom 404 page but encountered an error in the component itself.
- at async DevServer.renderErrorToHTML (/app/node_modules/next/dist/server/base-server.js:1589:32): The error rendering pipeline tried to show the 404 page but it also errored, creating a cascading failure.
Common Causes
1. Using getServerSideProps in 404 page
Custom 404 pages in the pages directory do not support getServerSideProps. Using it causes a build error.
export async function getServerSideProps() {
const suggestions = await fetch('/api/suggestions');
return { props: { suggestions: await suggestions.json() } };
}
export default function NotFound({ suggestions }) {
return <div>Page not found. Try: {suggestions.join(', ')}</div>;
}
2. Importing a client-only library at top level
The 404 page imports a browser-only library that crashes during static generation since 404 pages are statically rendered.
import confetti from 'canvas-confetti';
export default function NotFound() {
confetti(); // Crashes during SSG - no canvas available
return <div>404 - Page not found</div>;
}
3. Syntax error or type error in component
A simple coding mistake in the 404 page prevents it from compiling or rendering correctly.
export default function NotFound() {
const links = undefined;
return (
<div>
<h1>404</h1>
{links.map(l => <a key={l.href} href={l.href}>{l.text}</a>)}
</div>
);
}
The Fix
Remove getServerSideProps and any server-only dependencies from the 404 page. Custom 404 pages in Next.js are statically generated, so they must be simple components with no data-fetching methods. Use getStaticProps if you need data at build time.
export async function getServerSideProps() {
const suggestions = await fetch('/api/suggestions');
return { props: { suggestions: await suggestions.json() } };
}
export default function NotFound({ suggestions }) {
return <div>Page not found. Try: {suggestions.join(', ')}</div>;
}
import Link from 'next/link';
export default function NotFound() {
return (
<div className="flex flex-col items-center justify-center min-h-screen">
<h1 className="text-4xl font-bold">404</h1>
<p className="mt-4 text-lg">Page not found</p>
<Link href="/" className="mt-6 text-blue-600 hover:underline">
Go back home
</Link>
</div>
);
}
Testing the Fix
import { render, screen } from '@testing-library/react';
import NotFound from '@/pages/404';
describe('404 Page', () => {
it('renders the 404 heading', () => {
render(<NotFound />);
expect(screen.getByText('404')).toBeInTheDocument();
});
it('renders a link back to home', () => {
render(<NotFound />);
const link = screen.getByRole('link', { name: /go back home/i });
expect(link).toHaveAttribute('href', '/');
});
it('renders the page not found message', () => {
render(<NotFound />);
expect(screen.getByText('Page not found')).toBeInTheDocument();
});
});
Run your tests:
npm test
Pushing Through CI/CD
git checkout -b fix/custom-404-page-error,git add src/pages/404.tsx src/pages/__tests__/404.test.tsx,git commit -m "fix: simplify custom 404 page to avoid SSG errors",git push origin fix/custom-404-page-error
Your CI config should look something like this:
name: CI
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test -- --coverage
- run: npm run build
The Full Manual Process: 18 Steps
Here's every step you just went through to fix this one bug:
- Notice the error alert or see it in your monitoring tool
- Open the error dashboard and read the stack trace
- Identify the file and line number from the stack trace
- Open your IDE and navigate to the file
- Read the surrounding code to understand context
- Reproduce the error locally
- Identify the root cause
- Write the fix
- Run the test suite locally
- Fix any failing tests
- Write new tests covering the edge case
- Run the full test suite again
- Create a new git branch
- Commit and push your changes
- Open a pull request
- Wait for code review
- Merge and deploy to production
- Monitor production to confirm the error is resolved
Total time: 30-60 minutes. For one bug.
Or Let bugstack Fix It in Under 2 minutes
Every step above? bugstack does it automatically.
Step 1: Install the SDK
npm install bugstack-sdk
Step 2: Initialize
import { initBugStack } from 'bugstack-sdk'
initBugStack({ apiKey: process.env.BUGSTACK_API_KEY })
Step 3: There is no step 3.
bugstack handles everything from here:
- Captures the stack trace and request context
- Pulls the relevant source files from your GitHub repo
- Analyzes the error and understands the code context
- Generates a minimal, verified fix
- Runs your existing test suite
- Pushes through your CI/CD pipeline
- Deploys to production (or opens a PR for review)
Time from error to fix deployed: Under 2 minutes.
Human involvement: zero.
Try bugstack Free →No credit card. 5-minute setup. Cancel anytime.
Deploying the Fix (Manual Path)
- Run the test suite locally to verify the 404 page renders correctly.
- Open a pull request with the simplified 404 page.
- Wait for CI checks to pass on the PR.
- Have a teammate review and approve the PR.
- Merge to main and verify the 404 page works in staging.
Frequently Asked Questions
BugStack renders the 404 page in isolation, confirms static generation works, runs your test suite, and verifies the build succeeds before marking it safe.
Every fix is delivered as a pull request with full CI validation. Your team reviews and approves before anything reaches production.
You can use getStaticProps (not getServerSideProps) to fetch data at build time. The 404 page will be regenerated on each build with the latest data.
In the App Router, create app/not-found.tsx instead. It supports async data fetching natively since it runs as a server component, unlike the Pages Router 404.