Handling runtime errors when server side rendering with Next.js

Published on Tue Feb 09 2021
👆 That's not an error, it's an image 😁

Hero Image

👆 That's not an error, it's an image 😁

Avoid bad user experience by exploring different ways to manage runtime errors with Next.js

Intro

If you are working with Next.js, there is quite a good chance to bump into internal server errors (5xx) when on production. If not handled correctly, a single error can bring down the complete page. Imagine a user shopping online for their favourite gadget and they end up seeing this page. I’d never want this to occur on production as it would end up in a bad user experience.

Nextjs shipped SSG support with version 9.3 and brought in a lot of positives, including getting errors at build time rather than runtime. Switching from SSR to SSG, ended up in an amazing user experience as everything was statically generated before the site was deployed.

However, in some cases, we still require our website pages to use server side rendering (SSR) instead of static site generation (SSG). Example, checking if the user is logged in or not?

Plot

In this article, let’s take a look at a typical error, the “TypeError“

Consider our web-application consuming data from a CMS. At some point the marketing team tries to change a property and they accidentally end up removing one. Or, for the sake of this article let’s consider the CMS backend server goes offline. We fail fetching the data from the CMS and the TypeError is born.

This example considers a scenario when your webpage uses Server side rendering.

The source code for this article is deployed on https://ssr-error-handling-git-main.meetdave3.vercel.app and available on Github: https://github.com/meetdave3/ssr-error-handling

Let’s take a look of ways how can we avoid a webpage from crashing in production?

1. Error boundary

function Tile(props) {
return (
<ErrorBoundary FallbackComponent={ErrorFallback} key={props.title}>
<a key={props.title} href={props.link} className={styles.card}>
<h3>{props.error.title} &rarr;</h3>
<p>{props.para.para.para}</p>
</a>
</ErrorBoundary>
);
}

Since we’re using React, we are aware of using error boundaries as React exposes getDerivedStateFromError or componentDidCatch lifecycle methods so we can handle the errors.

This lifecycle method won’t run in Next.js as componentDidCatch does not work when using SSR

If an error occurs in the Error Boundary, the webpage will simply throw a 500 internal server error and result in an errored page.

This is an intriguing scenario since Next.js uses a client side library (React) and takes it to the server to render pages on demand.

Check: https://ssr-error-handling-git-main.meetdave3.vercel.app/error-boundary

You will see a 500 internal server error. Yes, it’s annoying and we don’t want our end users to see it either.

2. Try ... catch

When server side rendering, Our old friend Try … catch is a good replacement to the error boundary as it works expectedly on server side, helps us avoiding the annoying 500 internal server error.

You can wrap your risky component with a try catch like so

function Tile(props) {
try {
return (
<a key={props.title} href={props.link} className={styles.card}>
<h3>{props.title} &rarr;</h3>
<p>{props.para.para.para}</p>
</a>
);
} catch (e) {
// Send to an error monitoring solution or log it.
return null;
}
}

Check: https://ssr-error-handling-git-main.meetdave3.vercel.app/try-catch

and you can see how the complete page doesn’t crash any more.

3. Optional Chaining

function Tile(props) {
return (
<a href={props?.link} className={styles.card}>
<h3>{props?.error?.title} &rarr;</h3>
<p>{props?.para?.para?.para}</p>
</a>
);
}

This method is the best case from all the options when we want to solve a TypeError. It’s minimal, it’s fast, still it can only help us in accessing chained properties without throwing any error.

Conclusion

It’s not necessary to use any of these methods if you are statically generating the site (SSG)

Why? Because we will get the TypeError at build time when running `next build` and a production build won’t be created.

When using SSR, we need to fallback to the try .. catch solution when we are trying to do something more error prone like calculating the total tax of the shopping basket when rendering the checkout page.

It’s best to use a mix of optional chaining and try catch to avoid server side errors. Avoid falling into the trap of using React error boundaries when creating a server side rendered page.