Next.js: Cannot have an _error.tsx file without a 404.tsx file

Created on 27 Apr 2020  路  8Comments  路  Source: vercel/next.js

Bug report

Describe the bug

It isn't possible to have an _error.tsx file in the /pages folder without also having a 404.tsx file. When running next dev, it works fine, but as soon as you run next build, the following error appears:

Automatically optimizing pages ...
Error occurred prerendering page "/404". Read more: https://err.sh/next.js/prerender-error:
Error: Error for page /_error: pages with `getServerSideProps` can not be exported. See more info here: https://err.sh/next.js/gss-export

According to the official Next.js Blog, it should not be a problem to have a _error.tsx without a 404.tsx: https://nextjs.org/blog/next-9-3#automatic-static-optimization-for-404

The reason I do not want a static 404 page is so that I can catch routes with a trailing slash and redirect accordingly to the route without a trailing slash. This must be done on the server.

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Create an _error.tsx file with a getServerSideProps() function.
  2. Run next build.

Expected behavior

The error message says that it is trying to export the _error.tsx file even though it obviously shouldn't be. The application should still build. As soon as I add a 404.tsx file or remove the _error.tsx file, it builds without a problem.

System information

  • OS: macOS and Alpine Linux (Docker)
  • Version of Next.js: 9.3
  • Version of Node.js: 13.13.0 and 14.0.0

Additional context

Just in case it might be of any use, here is the code from my _error.tsx file:

import React, { useEffect } from 'react';
import { GetServerSideProps } from 'next';
import Head from 'next/head';
import Router from 'next/router';

import { makeStyles, createStyles } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';

import useStandardHeaderTags from '../lib/useStandardHeaderTags';
import TitleElement from '../components/TitleElement';

const useStyles = makeStyles(() =>
  createStyles({
    root: {
      textAlign: 'center'
    }
  })
);

interface Props {
  statusCode: number;
}

const Error: React.FC<Props> = ({ statusCode }) => {
  const classes = useStyles();
  const title = statusCode === 404 ? '404' : 'Error';

  return (
    <>
      <Head>
        {useStandardHeaderTags(title)}
      </Head>
      <Container className={classes.root}>
        <TitleElement text={title} />

        {statusCode === 404
          ? 'The page you are looking for could not be found.'
          : 'An error occurred.'}
      </Container>
    </>
  );
};

export const getServerSideProps: GetServerSideProps = async ({ res, req }) => {
  const statusCode = res ? res.statusCode : 404;

  if (statusCode === 404) {
    if (req.url.match(/\/$/)) {
      const withoutTrailingSlash = req.url.substr(0, req.url.length - 1);
      if (res) {
        res.writeHead(303, {
          Location: withoutTrailingSlash
        });
        res.end();
      }
      else {
        Router.push(withoutTrailingSlash);
      }
    }
  }

  return {
    props: {
      statusCode
    }
  };
};

export default Error;
story documentation

Most helpful comment

pages/_error can't use getServerSideProps on purpose as explained in https://github.com/zeit/next.js/discussions/11945#discussioncomment-6790. pages/404.js can't use getServerSideProps on purpose too as it massively increases server load without a good reason, eg all 404 routes would server-render on-demand with the code that you wrote.

Shouldn't be this up to the developer to decide? Feels like being too babysitted here. In our case we would like to serve different 404 pages depending on the language. Now I'm forced to use a useEffect inside the 404 page to trigger the language change, which shows a flash of the English version.

All 8 comments

Same as #12246

The reason I do not want a static 404 page is so that I can catch routes with a trailing slash and redirect accordingly to the route without a trailing slash. This must be done on the server.

What you're looking for seems to be https://github.com/zeit/next.js/issues/9081

pages/_error can't use getServerSideProps on purpose as explained in https://github.com/zeit/next.js/discussions/11945#discussioncomment-6790. pages/404.js can't use getServerSideProps on purpose too as it massively increases server load without a good reason, eg all 404 routes would server-render on-demand with the code that you wrote.

What we can do is improve the error message / documentation around it.

Thank you for the replies! What isn鈥檛 clear to me though is whether the redirects feature is already available in the latest version of Next.js as it was still marked as open. Also, is it possible to create a redirect with a regex-based src key so that I can redirect all routes with a trailing slash?

This issue is unfortunately holding up the launch our website...

I was, however, able to solve it by changing the getServierSideProps function to

Error.getInitialProps = ({ res, req, err }): Props => {
  const statusCode = res ? res.statusCode : err ? err.statusCode : 404;

  if (statusCode === 404) {
    if (req.url.match(/\/$/)) {
      const withoutTrailingSlash = req.url.substr(0, req.url.length - 1);
      if (res) {
        res.writeHead(303, {
          Location: withoutTrailingSlash
        });
        res.end();
      }
      else {
        Router.push(withoutTrailingSlash);
      }
    }
  }

  return { statusCode };
};

That works well.

pages/_error can't use getServerSideProps on purpose as explained in https://github.com/zeit/next.js/discussions/11945#discussioncomment-6790. pages/404.js can't use getServerSideProps on purpose too as it massively increases server load without a good reason, eg all 404 routes would server-render on-demand with the code that you wrote.

Shouldn't be this up to the developer to decide? Feels like being too babysitted here. In our case we would like to serve different 404 pages depending on the language. Now I'm forced to use a useEffect inside the 404 page to trigger the language change, which shows a flash of the English version.

Has this possibly been fixed?

I've just tested next with just index.js, _app.js and _error.js and it worked without a 404.js.

nvm, this bug is still present.
When _error.js has getInitialProps a 404.js is not required, but otherwise it is

Was this page helpful?
0 / 5 - 0 ratings