I have 2 themes, both enabled, assume they are called my_first_theme (default) and my_second_theme. I have /whatever path and lots of the pages under this path, and I have a theme negotiator, which sets my_second_theme as an active one for any page under this /whatever path, including nodes, views, custom controllers etc.

So far it works good. Problem is, when 404 or 403 is triggered, the theme used to generate the response is always the default one (my_first_theme).

What I need is when 404 or 403 response is generated for any path under /whatever path, I would like the my_second_theme to be used for those templates, not the default one. The only way to achieve it at this moment I see is that I create a copy of the frontend stuff under my_first_theme just to be used for 404 and 403 purposes, but that's definitely a dirty way to do that. Basically I will have a clone of my_second_theme assets under the my_first_theme folder just to serve 404 and 403 responses.

Few examples of what I would like to achieve:

  • /nonexistent404 - my_first_theme used
  • /exists/but/access/denied403 - my_first_theme used
  • /whatever/nonexistent404 - my_second_theme used
  • /whatever/path/exists/but/no/access403 - my_second_theme used

1 Answer 1


How does the theme negotiator get the path?

In a sub-request for a 403/404 error page you are probably looking for the path of the main request:

$main_request = \Drupal::requestStack()->getMainRequest();
$path = \Drupal::service('path.current')->getPath($main_request);
  • Unfortunately by the time the 404 error is handled, Drupal has already completed the theme negotiation process and set the active theme. This is why the theme negotiator does not affect the theme for 404 pages. I also tried to handle KernelEvents::EXCEPTION, without any luck, theme is already chosed by that time Jun 2, 2023 at 16:49
  • Did you try to get the path I suggested in applies() and determineActiveTheme() of your theme negotiator? I just tested it with my debugger and it stops there in the sub-request.
    – 4uk4
    Jun 2, 2023 at 17:07
  • Looking at the theme manager this service is global to the main request so it doesn't really matter when the theme is initialized. Important for a path-based theme negotiator is to get the path this way. Then you don't depend on the timeline. However, for a 404 this is very likely to take place in the sub-request because you are thrown out of the main request very early before any theming can happen.
    – 4uk4
    Jun 2, 2023 at 19:30
  • Okay so basically getMainRequest() is what I needed. Before that I was using $route_match, which was only working for existing routes and in case of 404/403 it was an instance of NullRouteMatch. Thanks for your help. Jun 2, 2023 at 19:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.