How can I throw a 404 error from within hook_menu_get_item_alter()?

If I call drupal_not_found() then it keeps calling itself, and I don't know an other way to do this.

2 Answers 2


I was able to do this in hook_menu_get_item() by getting the status of the node from a simple query, and, when status isn't NODE_PUBLISHED, I change the router item's load function from node_load() to is_null(), which will always return FALSE when a node ID is passed to it. A FALSE from a load function will result in a 404 response from Drupal. This is a bit dirty, but it uses the Drupal API properly, and it seems to work!

 * Implements hook_menu_get_item_alter().
function mymodule_menu_get_item_alter(&$router_item, $path, $map) {
  if ($path == $_GET['q']) {
    if (isset($map[0]) && $map[0] == 'node' && isset($map[1]) && is_numeric($map[1])) {
      $status = db_query('SELECT n.status FROM {node} n WHERE n.nid = :nid', array(':nid' => $map[1]))->fetchField();
      if ($status != NODE_PUBLISHED) {
        // Replace node_load() with is_null() as load function, to ensure the
        // output of the load function is FALSE, so we get a 404 response.
        $router_item['load_functions'] = array('is_null');      

You can't directly - data from hook_menu() and hook_menu_alter() are cached, so the decision can't be made there for individual page requests.

Instead, you need to override the page callback, e.g.

function MYMODULE_menu_alter(&$items) {
  $items['foo']['page callback'] = 'MYMODULE_foo';

function MYMODULE_foo() {

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.