We managed to break part of a Drupal 7 site the other day (in this instance Drupal 7.31). That’s not new. But for the first time, we actually had to edit the database by hand to fix the problem. That was new, and I thought I’d share the experience, and our solution, for the benefit of anyone struggling with the same problem.
We tend to use Drupal to build data-intensive sites, with lots of fields and inter-related content types. We use the Field Group module a fair amount to help us to present input forms and output displays in a structured manner (at the time this problem occurred, version 7.x-1.4). This makes the data easier to enter, and easier to read when presented.
The other evening, while my partner was using the field UI to re-organize the fields and field groups for a complex profile type, an error occurred. It is not clear whether she suffered an ajax error, or whether the field UI or the Field Group code has a bug. But at some point we could no longer reach the “Manage Display” page for the profile type at all — WSOD. Actual displays of individual profiles still worked, sort of, but most fields, and all of the field groups, were simply missing. And there was no way to fix the problem through the Drupal GUI. The page that would allow us to fix, or at least delete, the broken fields/field groups was the page broken BY the broken fields/field groups.
I tried to fix the broken profile type with the features module. I loaded up a relatively recent backup, used the backup to create a feature for the profile type, and then enabled that feature on the broken site. No joy.
After a brief round of cursing, sleuthing and debugging ensued. The server logs revealed that the manage display page was simply timing out without throwing any PHP errors, suggesting an infinite loop. Using xdebug on our local development box, I was able to track the loop down to field_ui_table_pre_render(). As written, the function lends itself to infinite loops:
while ($list) { ... [some code that does NOT guarantee that the $list array will become empty] }
So I’m surprised that similar problems don’t happen more often. After watching the loop run for a bit, it became clear that we had some bad configuration data in one or more of the field groups, which was preventing the loop from exiting. But I was not going to hack core, and I needed to fix the problem, pronto.
Field group configuration data is stored, not surprisingly, in a database table called field_group. One column of this table, “identifier”, gives you the name of the field group as well as the entity type and the bundle in which that field group is used. After backing up the database (again), I used my favorite database management tool to run:
DELETE FROM field_group WHERE identifier LIKE '%profile2|client%'
(the entity and bundle in question), and cleared the caches. Problem solved. Of course, we lost all of those field groups, but they were relatively easy to re-create.
I hope you never face the same problem!