Magento 1 - category view URL doesn't get routed, product view does

There's multiple reasons the category view page may return a 404. I'll get to the specific code in a minute, but high level you'll want to

  1. Make sure your URL includes a numeric ID paramater

  2. Make sure your category is set to "active" in the backend

  3. Make sure your category is the member of a root category list in the category management page

For me the best way to debug these problems is to get down into the code. The category URL routes to the following controller class

#File: app/code/core/Mage/Catalog/controllers/CategoryController.php

Specifically, the following viewAction method

#File: app/code/core/Mage/Catalog/controllers/CategoryController.php
public function viewAction()
{
    if ($category = $this->_initCatagory()) {
        //...code snipped for brevity...
    }
    elseif (!$this->getResponse()->isRedirect()) {
        $this->_forward('noRoute');
    }
}    

For starters, I'd temporarily add some debugging code to make sure your controller is routing to the correct place

public function viewAction()
{
    var_dump(__METHOD__);
    exit;
    //...
}

If you don't see the method name dumped to the browser with the above code in place, that means there's a rewrite or override conflict with another module.

If that checks out, as you can see from the method definition, if the _initCategoty method returns false, the category page will go to the no route 404 page. Jumping up to _initCategory, you can see there's three reasons why this might happen.

First

#File: app/code/core/Mage/Catalog/controllers/CategoryController.php
protected function _initCatagory()
{
    //...    
    Mage::dispatchEvent('catalog_controller_category_init_before', array('controller_action' => $this));
    $categoryId = (int) $this->getRequest()->getParam('id', false);
    if (!$categoryId) {
        return false;
    }
    //...
}

If there's no id paramater in the URL, the method will return false and you'll get a 404.

Next, Magento loads a category and runs the following

#File: app/code/core/Mage/Catalog/controllers/CategoryController.php
protected function _initCatagory()
{
    //...    
    if (!Mage::helper('catalog/category')->canShow($category)) {
        return false;
    }
    //...
}

There's a set of rules in canShow Magento runs the category through. If those fail, you get a 404 page. (we'll get to those rules in a second)

Finally, Magento dispatches a catalog_controller_category_init_after event

#File: app/code/core/Mage/Catalog/controllers/CategoryController.php
try {
    Mage::dispatchEvent(
        'catalog_controller_category_init_after',
        array(
            'category' => $category,
            'controller_action' => $this
        )
    );
} catch (Mage_Core_Exception $e) {
    Mage::logException($e);
    return false;
}

If any event observers throw an exception, Magento will log the error message and display a 404 page.

I'd recommend you add temporary debugging code above each return false

var_dump(__METHOD__ . '::' . __LINE__);
exit;
return false;

This will tell you which conditional is failing. For the exception, an extra

var_dump($e->getMessage());

is a good idea.

If it's canShow that's failing, you can find those tests in

#File: app/code/core/Mage/Catalog/Helper/Category.php
public function canShow($category)
{
    if (is_int($category)) {
        $category = Mage::getModel('catalog/category')->load($category);
    }

    if (!$category->getId()) {
        return false;
    }

    if (!$category->getIsActive()) {
        return false;
    }
    if (!$category->isInRootCategoryList()) {
        return false;
    }

    return true;
}

As you can see, this is where the checks for an active category, or ensuring the category is in the root list live. Similar debug code here should let you figure out what the exact problem is.


If this error were occurring for product pages, I would be inclined to look into a problem with URL rewrites and/or an issue with catalog module route configuration i.e. the contents of the frontend/routers/catalog xpath in config. That your products are working tells me that there is nothing universally broken with either of these two.

Errors, can you see them?

Depending on the error, Magento route-to-controller matching may not work for the standard router, in which case the 404 page will be displayed via the default router. I would start by ruling out core code changes and custom modules. Enable error reporting for PHP and set Magento developer mode to true; see index.php and edit directly, or set the necessary params prior to PHP (e.g. in .htaccess if you are using Apache). Check error logs in var/log/.

Core Changes

If possible, use a stock copy of your version of Magento, point it at the database, and see if the problem remains. If so, it's a data issue, which may come from code, but at least you'll have an indication of where to look.

Custom code

Back in the "regular" instance, rule out local-codePool modules by setting the disable_local_modules flag in app/etc/local.xml to true and test the effect (assuming that the declaration files in app/etc/modules/ follow convention and don't do anything besides declaring the module).

Community-codePool modules cannot be disabled this way, so it would be necessary to rename the community codePool temporarily to effectively disable them (again, assuming that the declaration files in app/etc/modules/ follow convention and don't do anything besides declaring the module). Test the effect and see what happens.

Magento routing normally works, so by iterating through the code and config which is used when routing, it's possible to winnow away culprits and help reveal the problem.


Generally, the best way in Magento to debug is to dig in the code and have a certain amount of patience :). First off all you have to figure out in what file the problem is generated (Or what table). Things like a debug toolbar and template path hints can easily point you in the right direction. Then you can move on to debugging in detail. I usually put a Mage::log in the functions to see what function is generated then I go deeper into the problem. If there are any table / query related problems you could always turn on $_debug and query logging (the latter is usually available in a debug toolbar). For debugging an indexer I advice you to trigger it from command line because it returns the errors more propperly. The rest is just digging, digging and digging but after a while it gets faster and faster.

The only other advice i can give you is try to solve as much as problems yourself, here in Belgium we have a simple saying called 'You learn while doing'.