Just now I did a CVS update, wiped database, and installed Drupal with the minimal/expert install profile.
Then I went to the Modules page and checked "enable" on all of the optional core modules except Overlay. Clicked Submit.
I got this error message on the results page, and I didn't have any of my sidebars etc. (the only working link on the page was in the header bar (the home page link):
FieldException: Attempt to create a field instance that already exists. in field_create_instance() (line 634 of /opt/www/eclipsework/drupal/modules/field/field.crud.inc).
It seems that all of the modules were successfully installed, but there's obviously some problem here that needs to be fixed....
Comment | File | Size | Author |
---|---|---|---|
#50 | 682552-defined-switch-1.patch | 941 bytes | mradcliffe |
#48 | 682552-defined-switch.patch | 939 bytes | mradcliffe |
#48 | 682552-define-isnew-disabled.patch | 1.15 KB | mradcliffe |
#45 | 682552-fixdoc-2.patch | 5.63 KB | jhodgdon |
#43 | 682552-fixdoc-2.patch | 5.63 KB | mradcliffe |
Comments
Comment #1
jhodgdonI'm also getting this same error again whenever I clear my caches from the Performance page.
Comment #2
jhodgdonI just did another wipe/cvs update/install. Error still occurring.
I put in a crude print statement in field_create_instance, and found that it is a collision between:
and
I don't know enough about that to continue debugging.
It's also interesting to me that after a while, the error messages stop happening.
Comment #3
yched CreditAttribution: yched commentedOdd. Cannot reproduce. Not a fresh-from-the-day install, though.
Comment #4
jhodgdonThe behavior I'm getting is that it happens a few times when I first install, and then I stop seeing the error message. It all seems very odd.
Comment #5
sun.core CreditAttribution: sun.core commentedAny updates?
Comment #6
jhodgdonI just tried it (wipe everything, install from HEAD, expert profile, check all core modules except Overlay and click Submit).
I'm still getting the same error.
Comment #7
jhodgdonCorrection: The error message is slightly different now:
FieldException: Attempt to create an instance of field comment_body on bundle comment_node_blog that already has an instance of that field. in field_create_instance() (line 645 of /opt/www/eclipsework/drupal7/modules/field/field.crud.inc).
Comment #8
jhodgdonLooking into this a bit more...
Places I see field_create_instance() being called with the 'comment_body' field:
1) comment_enable() in modules/comment/comment.install -- note that it's not in comment_install() but in comment_enable().
2) comment_update_7012() in modules/comment/comment.install
3) comment_node_type_insert() in comment.module
My guess is that #1 and #3 are conflicting (I don't think the update functions should be run if I'm doing initial module enable, correct?), but I'm not sure of the exact sequence of events... Let's see...
a) When I submit the modules form, system_modules_submit() calls http://api.drupal.org/api/function/module_enable/7
b) module_enable() first updates the modules db (setting status of each module to 1, indicating it's enabled). So at this time, both the blog module and the comment module will be enabled.
b) Then module_enable() calls each module's hook_enable(). Blog doesn't have one. comment_enable() at that time lists all content types with node_get_types(), finds 'blog' without a comment body field, and attaches the comment body field. Which would seem OK, except that node_types_rebuild() hasn't been called yet, so even though node_get_types() tells the comment module that the blog content type exists, it actually hasn't been run through node_type_save() yet.
c) Then module_enable calls a bunch of functions to reset caches, including node_types_rebuild(), which at this point calls node_type_save() on all the new content types (including blog), thus triggering the comment_node_type_insert() function, which doesn't bother to check to see if the comment body field already exists before attaching it. http://api.drupal.org/api/function/comment_node_type_insert/7
So. IMO, the problem is really that comment_enable() is assuming that the node types have been built, when in fact they haven't been built yet. Because comment_node_type_insert() should be able to assume it's getting a brand-new content type being saved for the first time (if it was a new content type, it should have been sent to hook_node_type_update() instead).
The fix is probably to have comment_enable() call node_types_rebuild() to ensure that the list of content types returned by node_get_types() is really accurate with what's been saved to the database. Or for node_get_types() to verify that everything is in the DB.
Comment #9
jhodgdonMinimal steps needed to reproduce this issue:
a) Create a new space (wipe database, cvs get D7 HEAD)
b) Run install.php and choose the "minimal" install profile.
c) Visit the modules page (admin/modules/list)
d) Check "Blog" and "Comment" and submit the form.
You will see the following error:
Comment #10
jhodgdonComment #11
jhodgdonThinking this over...
So the problem is that comment_enable() is assuming that node_get_types() is returning fully-created types (i.e. types that have been run through node_type_save()), because comment_node_type_insert() will take care of content types as they are created with node_type_save().
Actually, I think that in most cases, the functions that call node_get_types() and related functions will assume that the node types returned have been already run through node_type_save() at least once. So I'm going to create a patch that will assume that, but let the few cases where that isn't the case bypass that.
Comment #12
jhodgdonUgh.
Actually, I think that maybe the best thing is just for comment_update() to call node_types_rebuild() to make sure it's getting the right information.
Comment #13
jhodgdonHere's a patch that calls node_types_rebuild() in comment_update(), and adds doc to node_type_get_types() to warn others of this issue.
I've verified that with this patch, the reproduce steps in #9 do not produce the error message any more.
Just as a note, the reason I decided it wasn't a good idea to add automatic rebuild to node_type_get_types() is that it's really only an issue during module install, because node_types_rebuild() is always called during module install, and it would have added unnecessary overhead.
Comment #14
yched CreditAttribution: yched commentedUgh. Thanks for great detective work !
node_type_get_types() returning types that have not been 'inserted' yet (hook_node_type_insert() yet to be called) does sound like a WTF.
Not sure of the best fix at this time of the day :-/.
Comment #15
jhodgdonYeah, it's a definite WTF. However, it does only come up at install/enable module time, since module_enable() calls node_types_rebuild() a bit farther down in the function.
er.
I guess node_types_rebuild() is called from system_modules_submit() and not from module_enable().
Hrmmph. _install_module_batch() doesn't call node_types_rebuild() either. Hopefully install.php does it at some point...
Comment #16
David_Rothstein CreditAttribution: David_Rothstein commentedAny thoughts on whether it would be a good idea to take the node_types_rebuild() call out of system_modules_submit() and put it in module_enable() instead?
(That kind of thing is part of the overall project at #651086: Cache clearing is an ineffective mess in module_enable() and system_modules_submit() but who knows where that will end up, and if we have a specific bug here it seems like it might make sense to do it now...)
The installer should be covered, since it just calls drupal_flush_all_caches() at the end, as a catch-all for this kind of problem :)
Comment #17
jhodgdonMy feeling is that logically the best thing to do would be to build it into node_type_get_types() (or technically, the internal function that does the work for that and other functions), so that there would be no way to call node_type_get_types() and get the wrong answer (i.e. types that haven't been saved). This could probably be made fairly efficient with a flag saying "node types need rebuilding", which would have to be reset early in the module install process.
If that was done, then system_modules_submit() et all wouldn't even have to call node_types_rebuild(). Same thing could be done with menus, etc. if we had a hook_caches_are_all_wrong() or something like that, which is maybe what is being proposed in #651086: Cache clearing is an ineffective mess in module_enable() and system_modules_submit()?
But really, both of these seem like too big of a change for D7 at this point, which is why I proposed the patch in #13, which fixes the immediate problem with comment.module and documents the problem in the doxygen for node_type_get_types().
Comment #18
grendzy CreditAttribution: grendzy commentedI've verified that that this fixes the FieldException error. And the reply in #17 is convincing enough for me...
Comment #19
catch#13 looks good until #651086 is fixed (which might be D8 at this point).
Comment #20
Dries CreditAttribution: Dries commentedIt feels odd to call node_type_rebuild() in comment module, rather than calling it directly after the node type was created. Any reason for that? In fact, I thought the analysis/recommendation in #11 was right on.
Comment #21
jhodgdonDries: See #17 for my best idea of how to actually fix this... Would you support this type of change this late in D7 development? I think that's the best place to put it.
My idea in #11 of a simple fix was negated once I looked deeper into the code (see #13).
Comment #22
Dries CreditAttribution: Dries commentedI think we should try to fix this properly, even this late in the cycle. Seems like an important thing to get right.
Comment #23
jhodgdonOK. I can take a look at it early next week.
Or someone else can take it on if they have time earlier -- just assign it to yourself so I know it's not my project any more. :)
Comment #24
jhodgdonOK, I'll take this on now.
Comment #25
jhodgdonWell, maybe not. I give up... The fixes I attempted did not solve the problem, and I'm not sure what to do...
Note that the easy way to reproduce the problem is in #9.
Comment #26
jhodgdonFor reference, here's the patch I attempted. With this patch, the error I get when following #9 steps to reproduce is:
"FieldException: Attempt to create an instance of field body without a bundle. in field_create_instance() (line 627 of /opt/www/eclipsework/drupal7/modules/field/field.crud.inc)."
So it looks like this solves one problem but creates another. I really don't know what to do at this point, besides going back to the hackish patch in #13 that Dries didn't like.
Comment #27
mradcliffeThe changes that were made in #553306: Make nodes have no body field by default. Remove deprecated APIs for body field so far cause the patch in #13 not to work.
Also, every time I try the blog/comment thing above it creates a field instance no matter what. If you uninstall comment it doesn't remove the instance tables. So if you keeping doing enable/disable/uninstall you'll end up adding two tables every time (install adds 4 tables, and uninstall removes 2).
field_data_comment_body_N
field_revision_comment_body_N
field_config_instance correspondingly has N instance entries.
If I comment out the _comment_body_field_instance_create from comment.install (line 73) there's no exception anymore. Where the heck are the instances getting created (still searching...)?
Comment #28
jhodgdonIf you comment out _comment_body_field_instance_create(), the instances on the blog node type will be created when node_type_save() is eventually called from node_types_rebuild(). That is why in #9 reproduce you get the error (without the patch): comment_enable() creates the instance, and then node_type_save() does it again. (See #8 above for complete explanation of this sequence.)
So removing that line would fix the problem, but break the intended behavior of that line: you want to add the comment field to *existing* node types that existed before this round of module enablings.
The problem is that in comment_install(), you want only the old types to be added to, not node types that have yet to be added to the database (i.e. the ones that are defined in newly-enabled modules' hook_node_info() implementations, which are not saved to the database until node_types_rebuild() is called).
Does that make sense?
The thing about having multiple instances that aren't removed is a separate issue and should probably be dealt with separately.
Comment #29
mradcliffeYeah, I just spent the last 15 or so minutes working that out in a post I was about to make. ;-)
It would work if blog node type was created after comment_enable instead of before.
Is node_type_get_types() grabbing the blog node type before it's even created?
Edit: Yes. Blog node type isn't added to node_type database yet, but since the module code is loaded it's returned as a valid node type.
Comment #30
mradcliffeAfter talking on IRC and getting some food I'm not sure we should rewrite something as big as node_types_rebuild and _node_types_build this late in the development cycle. It may have some hefty effects.
Can't we just make it a one line fix and not do anything on
$info->is_new
and$info->disabled
?Comment #31
jhodgdona) Does that fix the problem? It looks fairly reasonable...
b) If we use this tactic rather than changing how node_type_get_types() et al work, I would advocate adding doc to all of the node_type_get_* functions, as well as _node_types_build(), detailing what their return value is in the case where the db is not synchronized with the hooks, and explaining that it wouldn't be synchronized during module install/enable hooks.
Comment #32
mradcliffeYes, it prevents comment.install from adding the field, and lets it be done in hook_node_type_insert instead.
Probably more documentation on using is_new and is_disabled to advocate using it.
Comment #33
vwX CreditAttribution: vwX commentedI've reviewed and tested this patch on the latest HEAD and can confirm that it does indeed fix the exception issue. I agree on the documentation comments, always a good thing.
Comment #34
mradcliffeThank you for your help, vwX.
Attached is some documentation about is_new and disabled to _node_types_build and to point to that method from the docs of other methods.
I'll set it to rbtc again after testing comes back.
Comment #36
mradcliffeThat looks like a testing bot goof. It passes Tracker module test here with updated head. Re-rolling patch just in case.
Comment #37
jhodgdonI think the doc could be better...
- The field explanation needs more detail, and should explain
- Several of the functions do not give you those fields to check.
- Just having @see _node_types_build() and having the doc on node_types_build() does not seem like a very good way to warn users of those functions, who might not bother to jump to that other page/function and see the doc. So I think the warning should be on all of those node_type_get_* functions too.
I can give the doc a work-over on Monday, unless someone gets to it before me....
Comment #38
jhodgdonHere's a new patch, with more doc explanation, preserving the fix for the bug from #36.
Comment #39
jhodgdonWhoops. Try this one (a few minor typographical corrections in the doc)
Comment #40
mradcliffeThank you for expanding on that, jhodgdon. I think the expanded docs to _node_types_build will definitely help for debugging any future issues that people run into.
I'm going to move this to RTBC from vwX's, your, and my testing, and hopefully Dries can take a look at this from #22 to get this critical issue done.
Comment #41
grendzy CreditAttribution: grendzy commentedThis doc change isn't clear...
136 critical left. Go review some!
Comment #42
jhodgdonbe -> not
Sorry about that.
Comment #43
mradcliffeMade change, read over again, ran by spellcheck, re-rolled.
Comment #44
jhodgdonOne more fix needed:
Last line
obsolete types -> and obsolete types.
(again, my fault, sorry)
I must run out, so cannot reroll right now, sorry.
Comment #45
jhodgdonOh wait, I don't have to leave for an hour. Here's a revised patch.
Comment #46
catchPatch looks good, fix is one line, lots of comments. This will be either annoying or impossible to test until we stop relying on the default profile for testing, so it should go in as a quick fix.
Comment #47
Dries CreditAttribution: Dries commentedOK ... Committed to CVS HEAD. Thanks.
Comment #48
mradcliffeOh, crap. I feel terribly dumb. There are cases where is_new and disabled are undefined leading to the following warnings.
If node_set_type_defaults() isn't called and the type isn't new, then is_new is never defined. Even if it is called disabled isn't defined either (as false). When looking at existing node types is_new isn't defined (as false).
We probably need even more documentation, tests, and defining these two variables to make sure that nothing is left undefined. I think that having undefined variables in certain cases is a bit odd if they're boolean. It also seems a bit blah that one is set to FALSE and the other is set to 1/0. Should they remain consistent?
The other idea, since they're either in a defined or undefined state, is to change the ! to isset().
Attaching a couple of patches, setting to review for a test, and then setting back to needs work afterward.
Comment #49
mradcliffeThe other conditionals in node.module with is_new and disabled use isset().
Should additional documentation be split into two places?
node_type_set_default (which i dyslexiafied last post ;-) for is_new and _node_types_build for disabled? Or just expand the documentation for _node_types_build?
Comment #50
mradcliffeUGH, I just realized that the defined patch above is backwards. Whoops, sorry for spam.
Comment #51
catchComment #52
Dries CreditAttribution: Dries commentedCommitted to CVS HEAD. Thanks.