I've created a custom error handler for 404 errors (page not found).

I've set up Home » Administration » Configuration » System » Error Pages for 404 errors to point to http://example.com/myerrorpage, and then I have the following in hook_menu

 * Implements hook_menu().
function MYMODULE_menu() {
  $items = array();
  $items['myerrorpage'] = array(
    'title' => 'myerrorpage',
    'access callback' => TRUE,
    'page callback' => 'myerror_page',
    'theme callback' => 'myerror_theme',
    'type' => MENU_CALLBACK,
  return $items;

When I enter a non-existing path (e.g. http://example.com/bogus) the page callback is invoked as expected.

However, the theme callback is not.

To get the theme callback to fire, I need to enter the following path: http://example.com/myerrorpage.

I do not understand why the theme callback does not fire at the same time as the page callback.

Is there any way to get the theme callback (or hook_custom_theme()) to fire when a non-existing path is given?

  • 1
    Looks like a bug in core for me. I would expect it to work just like aliases do.
    – Mołot
    Commented Aug 6, 2014 at 13:54
  • At first glance this actually does look like a bug (or at least an undocumented limitation) - menu_get_custom_theme() is called earlier in the bootstrap then drupal_deliver_html_page(), so overriding the menu item to the 404 page in that second function can have no effect on the current theme callback
    – Clive
    Commented Aug 6, 2014 at 15:01
  • As a nasty hack you could provide your own delivery callback function and unset($_GLOBALS['theme']); drupal_theme_initialize(); between the calls to menu_set_active_item() and menu_execute_active_handler(). Not pretty, but it should work
    – Clive
    Commented Aug 6, 2014 at 15:06

1 Answer 1


In menu_get_custom_theme(), you can see that theme callback on menu router would not be called if the menu router doesn't exist. But you can achieve that with hook_custom_theme().

I'll go like this:

 * Implements hook_custom_theme().
function MYMODULE_custom_theme() {
  $router_item = menu_get_item();
  if (empty($router_item)) {
    return 'THEME_NAME';

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.