Let's start with a few basic assumptions, a good error page is:

  1. Branded
  2. Helpful
  3. Localized
  4. Fast

Out of the box, AEM uses Sling's default error page. Most projects, however, will overlay sling/servlet/errorhandler/404 to create a branded error experience. This can cause performance problems with Dispatcher. Let's look at a typical go-live example.

  1. A user requests /us/en/sup.html
  2. Dispatcher doesn't have it in cache, so it must...
  3. Ask Publish if it has the resource
  4. Publish returns our branded 404.
  5. Dispatcher will not cache any error documents.
  6. Apache sends the user the branded 404 at the original request path.

This creates several problems. The big one? The request lifecycle above is for every request. This means we're constantly talking to Publish when a document 404s. What happens if a marketer sends out a bad URL? You'll DDoS yourself.

By combining a few clever configs, we can achieve our four original tenets for a good error page. Let's look at the first request:

  1. Our user requests a page.
  2. Dispatcher does not have it in cache. It must check with Publish.
  3. Publish doesn't have the page in question.
  4. Publish serves up the default Sling error page (it's... not attractive).
  5. Dispatcher identifies the error, doesn't cache, but let's Apache handle the request with the ErrorDocument directive.
  6. Dispatcher makes another Publish request based on the ErrorDocument path.
  7. Publish responds with a 200 and our branded 404 error page.
  8. Dispatcher caches the new 404 page.
  9. Apache delivers our 404 content at the original location (with the correct 404 status code).

This approach may seem complex, but let's take a look at every subsequent request:

In every following request, Publish can be hyper-efficient responding to 404s with the default Sling error page, but dispatcher will continue to keep the branded and localized version in cache for fast delivery. No more rendering of components for every error.

So, how can we achieve this? Let's start with the AEM layer.


This is the easy part. Your 404 page can be a simple content page built with your components. You build this page as you would any other. Want search? Add a search component. Want a sitemap, add your sitemap component. Best of all, this can follow your typical localization process to propagate to all other locales and languages.


With Dispatcher, we need to change our http.conf to let Dispatcher pass the error to Apache. Take a look at line 24:

This let's us pass only our status code to Apache and tells it to deal with the error.

Important Note: I would strongly recommend only specifying the error codes you have HTML content for. There may be scenarios where you deliver a 500 and a JSON string to be handled client-side (handlebars, angular, etc.).


Our final piece. As of Apache 2.4.12, you can use 'variables' with an ErrorDocument. Here's how we can deliver our localized error pages:

By using an if statement and routing our locale, we can insert the correct ErrorDocument for a given locale.

Additional Reading