August 29, 2011

Drupal debugging story: Rules defined in multiple Features

August 29, 2011 - Categories: drupal, geek, story

Fatal error: Unsupported operand types in …../patched/rules/rules/rules.module on line 347

That was the error message Daniel sent me when he asked for my help in debugging. After some digging, I found out that the rules had been defined in two features, so Drupal got thoroughly confused. After I commented out one of the implementations of hook_rules_defaults and deleted the relevant rows from rules_rules in the database, the site worked again.

Daniel wanted to know how I figured out that problem, so here’s the story.

The line number told me that rules_sort_children was having problems. I added a var_dump to it so that I could find out what kind of unexpected data was causing the errors.

if (!is_numeric($element[$key]['#weight'])) { 
  var_dump($key, $element[$key]['#weight']); 
}

The output showed that the regular rules were fine, but our custom rules weren’t – weight was an array instead of an integer.

I looked at the difference between the features in code and the features in the database. The rules were being duplicated. I tried updating the features to match the information in the database, but the code looked wrong, so I used git to stash the changes. I also tried reverting the features, but that didn’t solve the problem either. Time to dig deeper.

I backed up the database, then deleted our custom rules from rules_rules. Still problematic. I commented out the rule definitions in our site_structure.features.inc. The rules administration page now successfully displayed – but mysteriously, the rule definitions were still available.

I looked at the rule tags to see where else they might be defined, and found that another feature had included the rules. Aha! I commented those out. As expected, the rules disappeared from the administration page. I’d identified the problem: the rules had been defined in more than one module, which had thoroughly confused Drupal.

Because it made more sense to define the rules in our site_structure feature than in the other feature, I uncommented the site_sitestructure_rules_defaults definitions and left the other feature’s rules commented. That worked.

I tried restoring the rule customizations from the database, but that gave the same error. The database copy had multiple definitions, and I didn’t feel up to picking my way through the data or writing a Drush script to manipulate the rows. I re-deleted the customizations to get a clean copy. Just in case the other feature had more recent definitions of the rules, I compared the two. Aside from the extra tag, they were identical, so I didn’t need to copy any information over. It meant that Daniel would have to make his changes again, though.

Features: When it’s good, it’s very very good. When it’s bad, it results in quirky bugs. Make sure you don’t define your rulesets in multiple features. Drupal Features still has some rough spots when it comes to Rules. I remember when I created this feature with the rules in it – it created duplicate rules, so I needed to delete the old ones. Still, it’s a great way to export rules and other configuration changes to code, even though it takes some getting used to (and the occasional bit of database-diving).

Anyway, that’s the story of how I identified that issue and worked around it.

When you’re faced with a fatal error involving unsupported operand types, figure out what kind of operands it expects and print out anything that doesn’t match. Then you can start figuring out the real problem, which is how that data got in there in the first place. I’ve used this to find form elements that were mistakenly defined, array elements that were unexpectedly null, and so on. Don’t be afraid to add debugging code to core or contributed modules, particularly if you can use source code control to restore a clean copy. If you use a runtime debugger like XDebug, you can easily explore the data and the call stack. If not, there’s always var_dump.

Hope that helps!