Implementing a Custom 500 Error Page in Sitecore XM Cloud (Next.js Multi-site)
When building a multi-site solution on Sitecore XM Cloud, user experience is just as important during failures as it is when everything works. A properly implemented 500 Internal Server Error page ensures that even unexpected errors are handled gracefully, keeping users engaged and preserving brand consistency.
In this article, we’ll go through how to implement a custom 500 error page in an XM Cloud headless setup that supports multiple sites.
Why You Need a Custom 500 Page
In a traditional Sitecore XP site, custom error pages are usually handled by IIS or custom pipelines.
However, in XM Cloud (headless + Edge delivery):
- Rendering is done through a Next.js front end.
- Backend logic and errors may come from Layout Service or GraphQL API.
- The project might host multiple sites on the same XM Cloud instance.
A default 500 response (blank screen or technical message) gives no clue to users.
Instead, we’ll create branded, site-specific 500 error pages that:
- Match each site’s design.
- Display friendly fallback content.
- Allow tracking or logging (optional).
Architecture Overview
Understand the Context
In Sitecore XM Cloud (Headless with Next.js), server-side or rendering errors (e.g., GraphQL, Layout Service, API issues) lead to a 500 error.
Get Santosh Kumar’s stories in your inbox
Join Medium for free to get updates from this writer.
By default, the pages/500.tsx (or app/500/page.tsx in the app router) in your Next.js app handles these cases.
XM Cloud starter repo comes up with default 404 and 500 pages but there is limitation with next js implementation. You can find detail discussion for error page limitation in this github channel here
We can override this file to:
- Show a friendly error message
- Load site-specific content from Sitecore
- Optionally use a shared fallback if the current site has no 500-page content
Create a Dedicated 500 Error Page Component
In your Next.js app, under src/pages/500.tsx (or src/app/500/page.tsx if app router), create this file:
// src/pages/500.tsx
import { ComponentPropsContext, SitecoreContext } from '@sitecore-jss/sitecore-jss-nextjs';
import { LayoutServiceData } from '@sitecore-jss/sitecore-jss-nextjs';
import { componentFactory } from 'temp/componentFactory';
import Layout from 'src/Layout';
import { GetStaticProps } from 'next';
import config from 'temp/config';
import { getPublicUrl } from 'lib/utils';
import { siteResolver } from 'lib/site-resolver';
type Props = {
layoutData: LayoutServiceData | null;
siteName: string;
};
const Custom500 = ({ layoutData, siteName }: Props) => {
// Static fallback if Sitecore layout not found
if (!layoutData?.sitecore?.route) {
return (
<div className="flex h-screen items-center justify-center text-center">
<div>
<h1 className="text-4xl font-bold mb-4">Something went wrong!</h1>
<p>We’re working to fix it. Please try again later.</p>
</div>
</div>
);
}
// Render Sitecore-managed layout if available
return (
<ComponentPropsContext value={layoutData.sitecore.context}>
<SitecoreContext componentFactory={componentFactory} layoutData={layoutData}>
<Layout layoutData={layoutData} siteName={siteName} />
</SitecoreContext>
</ComponentPropsContext>
);
};
// Fetch site-specific 500 error page from Sitecore Layout Service
export const getStaticProps: GetStaticProps = async (context) => {
try {
const hostname = context?.previewData?.hostname || config.siteName;
const site = siteResolver.getByHost(hostname);
const siteName = site.name;
const errorPagePath = '/error/500'; // path under each site (e.g., /site1/error/500)
const response = await fetch(
`${getPublicUrl()}/sitecore/api/layout/render/jss?item=${errorPagePath}&sc_site=${siteName}`
);
const layoutData = await response.json();
return {
props: {
layoutData,
siteName,
},
};
} catch (error) {
console.error('Error fetching 500 page layout:', error);
return {
props: {
layoutData: null,
siteName: config.siteName,
},
};
}
};
export default Custom500;Sitecore Content Setup
In Sitecore XM Cloud:
- For each site, create a 500 Error Page item, e.g.
/sitecore/content/<YourSite>/Home/Error/500 - Assign your page design / component composition to display a friendly message.
- Ensure the item is published and accessible via Layout Service (no access restrictions).
Optional — Global Fallback
If some sites don’t have a /error/500 item, add a fallback:
const errorPagePath = `/sitecore/content/${siteName}/Home/Error/500`;
let response = await fetch(`${getPublicUrl()}/sitecore/api/layout/render/jss?item=${errorPagePath}&sc_site=${siteName}`);
if (!response.ok) {
// fallback to shared/global 500 page
response = await fetch(`${getPublicUrl()}/sitecore/api/layout/render/jss?item=/sitecore/content/Shared/Error/500&sc_site=default`);
}This will always work correctly in XM Cloud multisite setups — as long as:
- You have a
/error/500item in each site root, and - A global
/error/500under thedefaultsite for fallback.
Key Takeaways
- Use the default
pages/500.tsxto define your error-handling logic in Next.js. - Fetch the site-specific
/error/500layout usingsiteResolverto ensure the correct site context. - Implement a global fallback for shared error handling across sites.
- Use
ComponentPropsContextandSitecoreContextto render components consistently with other Sitecore pages. - Keep the error pages lightweight, with minimal dependencies and no personalization logic.
Extending the Same Approach
The same architectural approach and logic can also be applied to handle 404 (Page Not Found) scenarios in XM Cloud multi-site setup.
You can configure a site-specific /error/404 item and use a similar layout-fetching mechanism within pages/404.tsx.
💡 My colleague Shrikant Sahu has already published a detailed guide on implementing a custom 404 error page in Sitecore XM Cloud — covering setup, configuration, and code-level details.
Official Documentation References
For further reading and deeper understanding, check out these resources:
- 🔗 Sitecore XM Cloud Documentation
- 🔗 Next.js Custom Error Pages (500, 404, etc.)
- 🔗 Sitecore JSS for Next.js — Layout Service Rendering
Thanks for reading! Feel free to connect or leave feedback.








