Am I in the right place
If you are
- building a NextJS (pages) site
- using SSG with GetStaticProps (GSProps) with data from a CMS or similar source
- unsure how best to handle errors in your GSProps function
…then definitely keep reading.
If people are interested in a similar article for SSG with the app directory please lmk.
Let’s start with an example of what NOT to do (at least in 90% of cases):
export const getStaticProps = async (context) => {
try {
const cmsData = await getCmsData(context)
return {
props: {
cmsData,
},
revalidate: MY_REVALIDATE_TIME,
};
}
catch {
return {
notFound: true,
}
}
};
So what seems to be problem?
Seems obvious when it is pointed out… it’s the “return notFound”.
If any of your functions to fetch data or perform operations in the GSProps function throw, you’re going to have the following issues depending on when that error occurs:
GSProps error occurs at build: Your build will succeed. Whichever paths threw, will return 404 when you try to visit them. Yikes.
GSProps error occurs during a post-build revalidation (because you're using on-demand or time-driven revalidation): A page that previously generated successfully that throws on subsequent regeneration will change from a healthy page to a 404 page. Even bigger yikes.
The fallback
property defined against the corresponding getStaticPaths will determine whether this issue is confined to the already built pages (fallback = false), or if it extends also to pages that are statically generated after build time (fallback = blocking or true).
Unless you’re checking whether the page still exists, most likely you don’t want to return the 404 page when there is an error caught in your GSProps function.
So whats the fix? Throw! And to be polite to future codebase contributors who may not be privy to this information, make sure to leave a comment explaining why you’re throwing, and log to your monitoring solution of choice if you use one:
export const getStaticProps = async (context) => {
try {
const cmsData = await getCmsData(context)
// If our data retrieval is successful, but no data is collected
if (!cmsData) {
return {
notFound: true,
}
}
return {
props: {
cmsData,
},
revalidate: MY_REVALIDATE_TIME,
}
} catch (error) {
// Do not try to recover from this error so that Next
// can use the previously cached version of this page
// or to flag this issue in build
logger.error(`Error fetching CMS data: ${error}`)
throw error
}
}
This approach will now give you the following outcomes depending on your setup and the time of error:
GSProps error occurs at build: Your build will fail. The logs should explain why, allowing you to resolve the issue before it is shipped to production.
GSProps error occurs during a post-build revalidation: GSProps will throw when the error happens, the page is not recreated which would replace the previously cached version of the static page.
Put another way – You can throw and leave the error "uncaught" in your GSProps function to adopt Next's behaviour to use the last successfully generated version of the page if an error occurs during revalidation – a useful tool that can be used where many people would default to use the "notFound" approach.
One thing you will notice here is that we’re still returning notFound: true
if our data is false-ish. This could be the case if your page data was deleted in a CMS or external data store causing the fetch to end successfully, but not return data. Because the page's data no longer exists, now we should return the 404. It's worth noting that this depends on your fetcher function – I've assumed here that it ends successfully where the page no longer exists which it might not. Take care to perform proper analysis for each scenario whether you want either to return a 404, or throw to use the previously cached page.
Top comments (0)