Skip to main content
Level 1
April 23, 2026
Question

Implementing 404 error handler.

  • April 23, 2026
  • 4 replies
  • 44 views

404 error handler is implemented by overlaying the 404 from /libs/sling/servlet/errorhandler/404.jsp but changes 404.jsp to 404.html. And Java class to handle the request. on Dispatcher enabled below two flags
<IfModule disp_apache2.c>
        # Enabled to allow rewrites to take affect and not be ignored by the dispatcher module
        DispatcherUseProcessedURL    On
        # Default setting to allow all errors to come from the aem instance
        DispatcherPassError        1
  </IfModule>
Java class have  -

import com.adobe.cq.sightly.WCMUsePojo;

public class PageNotFound extends WCMUsePojo {

    @Override

    public void activate() throws Exception {

        getResponse().setStatus(404);

        getResponse().setContentType("text/html");

        getResponse().setHeader("Dispatcher", "no-cache");

        getResponse().setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");

        getResponse().setHeader("Pragma", "no-cache");

    }

}
And html have  -

<sly data-sly-use.pageNotFound="com.aem.core.errorHandler.PageNotFound"></sly>

<sly data-sly-resource="${'/content/aem/us/en/404/jcr:content' @ wcmmode='disabled'}"></sly>

This implementation works good on local but on qa environment it is going to default.jsp under errorhandler.

 Actula requirement is page shouldn’t redirect to 404.html but content is served from that page.

Can someone let me know the root cause for this issue?

4 replies

Mani_kumar_
Community Advisor
Community Advisor
April 23, 2026

Do not rely only 404.html.

This may be the reason local can work but QA fails. A request in QA may come through Dispatcher/rewrite with a different request form, extension, or resolution path, so your 404.html handler is not selected and Sling falls back to default.jsp. The standard documented customization path is the /apps/.../404.jsp overlay.

 

Have custom 404.html approach with /apps/sling/servlet/errorhandler/404.jsp, add /apps/sling/servlet/errorhandler/default.jsp as fallback, and include the authored 404 page content from there while keeping response status = 404.

Adobe Employee
April 23, 2026

@SaiMu1 
The most likely root cause is on the AEM/Sling error-handler side, not Dispatcher.

Your QA request is reaching Sling's error handling, but your custom 404 handler is either not being selected correctly or it is failing while rendering, so Sling falls back to the default error handler (default.jsp). That fallback behavior is standard when Sling cannot resolve a usable custom handler. The documented customization model is to overlay the error handler under /apps/sling/servlet/errorhandler, typically starting from 404.jsp, and Sling uses its normal script resolution rules to pick the handler. If no suitable handler is resolved, Sling uses the default handler.

https://experienceleague.adobe.com/en/docs/experience-manager-65/content/implementing/developing/platform/customizing-errorhandler-pages

https://sling.apache.org/documentation/the-sling-engine/errorhandling.html

 

Sanket_Kumbharkhane
Level 4
April 23, 2026

QA shows default.jsp because Sling isn’t using your custom 404 handler. When it can’t find (or can’t run) a handler for that status, it falls back to default.

Why it works locally but not on QA

  1. 404.html under errorhandler is flaky
    Docs and real-world setups assume 404.jsp. A 404.html HTL script might resolve on one environment and not another (AEM/SP version, script engines, how the node is packaged). If Sling doesn’t treat it as the 404 handler, you get default.jsp.

  2. Publish vs what you actually deployed
    Most common: the overlay (/apps/sling/servlet/errorhandler/...) and/or the bundle with PageNotFound isn’t on QA Publish the way it is locally (wrong package, runmodes, only author, etc.).

  3. Handler blows up at runtime
    If data-sly-use can’t load the class or activate() throws, the error page render can fail; then behavior gets weird. Check error.log on QA.

  4. Dispatcher flags aren’t the smoking gun
    DispatcherPassError 1 and DispatcherUseProcessedURL On don’t explain “always default.jsp” by themselves. They’re not a substitute for “handler exists and Sling resolves it.”

Probable solution: 

  • Ship a thin 404.jsp under /apps/sling/servlet/errorhandler/ that sets 404 + headers and includes/forwards to your real /content/.../404 experience (no redirect unless you add one).
  • Confirm on QA Publish: that node exists, 404.jsp is there, and the OSGi bundle with PageNotFound is active.
PGURUKRISHNA
Level 5
April 27, 2026

Hey ​@Mani_kumar_ , The issue is that Sling's error handler resolution is filename-based, and your 

404.html

 is not being picked up on QA because:

  1. Sling looks for error handler scripts by status code and request extension. When the request doesn't have an 

    .html
     extension (e.g., 
    /content/nonexistent
    ), Sling may fall back to 
    default.jsp
     instead of your 
    404.html
    .
  2. The error handler script naming convention matters: Sling resolves handlers by matching the response status code to script names under 

    /apps/sling/servlet/errorhandler/
    . It prefers 
    .jsp
     over 
    .html
     in certain resolution orders, and the selector/extension of the original request influences which script is selected.
  3. On your local instance, Dispatcher is likely not in the picture, so the request hits AEM directly and your handler works. On QA with Dispatcher, the 

    DispatcherPassError 1
     setting passes the error back, but the request URI/extension may differ, causing Sling to resolve 
    default.jsp
     instead.

Fix

1. Rename 

404.html

 back to 

404.jsp

 but use HTL (Sightly) syntax inside it:

Sling error handler resolution is more reliable with 

.jsp

 extension. Despite the file extension, you can still use HTL by creating a Sling Servlet or keeping the 

.jsp

 as a thin wrapper.

2. Better approach — use a Sling Error Handler Servlet instead of a script:

Create a servlet registered as an error handler:

Pagidala GuruKrishna