Problem/Motivation
Saving a registration_settings entity can fatal in the registration_waitlist submodule when the capacity is increased. During the registration_settings update event, the waitlist event subscriber assumes a host entity exists on the RegistrationSettings object and calls getSetting() on null, causing a fatal error.
This blocks registration owners from updating registration settings and results in the generic “unexpected error” message on save.
This only occurs when the conflict module is installed and enabled.
Steps to reproduce
- Enable the
registrationandregistration_waitlistmodules. - Create a host entity configured for registration (for example, an Event node using a registration type).
- Open its registration settings, set capacity to a non-zero value, and save.
- Edit the existing registration settings entity, increase capacity, and save.
- Observe a fatal error:
Call to a member function getSetting() on nullinRegistrationSettingsEventSubscriber::onSettingsUpdate()(line 64).
Error shown on save:
The website encountered an unexpected error. Try again later.
Error: Call to a member function getSetting() on null in Drupal\registration_waitlist\EventSubscriber\RegistrationSettingsEventSubscriber->onSettingsUpdate() (line 64 of modules/contrib/registration/modules/registration_waitlist/src/EventSubscriber/RegistrationSettingsEventSubscriber.php).
call_user_func() (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch() (Line: 57)
Drupal\registration\RegistrationStorage->invokeHook() (Line: 564)
Drupal\Core\Entity\EntityStorageBase->doPostSave() (Line: 781)
Drupal\Core\Entity\ContentEntityStorageBase->doPostSave() (Line: 489)
Drupal\Core\Entity\EntityStorageBase->save() (Line: 806)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (Line: 354)
Drupal\Core\Entity\EntityBase->save() (Line: 293)
Drupal\Core\Entity\EntityForm->save() (Line: 63)
Drupal\registration\Form\RegistrationSettingsForm->save()
call_user_func_array() (Line: 129)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers() (Line: 67)
Drupal\Core\Form\FormSubmitter->doSubmitForm() (Line: 597)
Drupal\Core\Form\FormBuilder->processForm() (Line: 326)
Drupal\Core\Form\FormBuilder->buildForm() (Line: 73)
Drupal\Core\Controller\FormController->getContentResult() (Line: 39)
Drupal\layout_builder\Controller\LayoutBuilderHtmlEntityFormController->getContentResult()
call_user_func_array() (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 637)
Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 121)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 53)
Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle() (Line: 116)
Drupal\page_cache\StackMiddleware\PageCache->pass() (Line: 90)
Drupal\page_cache\StackMiddleware\PageCache->handle() (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 741)
Drupal\Core\DrupalKernel->handle() (Line: 19)
Proposed resolution
Fix the getValue method of the HostEntityItem class to work properly. This method is called by the conflict module. The method is not used internally, so the problem has been hidden.
Add tests to ensure the problem stays fixed.
| Comment | File | Size | Author |
|---|
Issue fork registration-3565802
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
john.oltman commentedThanks @joel - can you clarify - does the Event node still exist, or was that deleted along the way.
Comment #3
joelpittetSorry, still debugging trying to create a failing test, don't look behind the curtain :D
Comment #4
joelpittetFor a bit more context: this originally showed up on a D7 → D10 migrated site, so that’s my first suspect. That said, it’s not limited to migrated content — I can create a brand-new Event node on that same site, enable registration, and still reproduce the fatal.
I haven’t been able to trigger it yet on a fresh D11 site, either manually or via a test, so I’m digging into what’s different between the environments.
@john.oltman — to answer #2 directly: yes, the Event node does still exist.
Comment #5
joelpittetBecause a picture is worth a 💯 words, this was my migration D10 site, new Event node (not migrated), save of the capacity change:

Comment #6
joelpittetInteresting if I save this with the CLI there is no error...
ddev drush php:eval '$s=\Drupal::entityTypeManager()->getStorage("registration_settings")->load(687); $s->set("capacity", 15); $s->save();'687is myRegistrationSettingsid for my new (un-migrated) event node "CS Lunch-Hour Art & Craft 2 - Electric boogaloo" and15was just the next number from it's previous capacity.I am dumping some logs to see along the code path where this is going wrong in the UI, but host entity is in the db, just missing when asked for it through the event subscriber.
Comment #7
john.oltman commentedThanks for digging into it - I'll try and reproduce on my test D10 system as well
Comment #8
joelpittetThe logs show the entity loads fine but
HostEntityItem::ensureCalculatednever logged, which implies the computed field isn’t being computed in the UI path. That points toRegistrationSettings::getHostEntity()usingisEmpty()and short‑circuiting before the computed field calculates.Comment #9
joelpittetWhile I think we could provide a patch here to mitigate this issue. The culprit is *ironically* the https://www.drupal.org/project/conflict module.
The stack shows
Drupal\conflict\Entity\ContentEntityConflictHandler::autoMergeNonEditableFields()callingHostEntityFieldItemList->setValue([])which then propagates toHostEntityItem->setValue([])and wipes the computed entity.Details:
conflict/src/Entity/ContentEntityConflictHandler.php:452→autoMergeNonEditableFields()setting the list to empty.registration/src/Plugin/Field/HostEntityFieldItemList.php:59and thenregistration/src/Plugin/Field/FieldType/HostEntityItem.phpto set the entity to NULL.preSave()filters the item as empty, leaving the list empty andvalueComputed = TRUE.I am happy with whatever you'd like to do with this issue @john.oltman?
listin\Drupal\registration\Plugin\Field\HostEntityFieldItemList::reset()and setting$this->valueComputedback tofalseif it's empty.?I'll make an issue/stink over there and link back here for context
Comment #10
joelpittet#3566032: autoMergeNonEditableFields() clears computed entity reference fields Is where I have moved.
Comment #11
john.oltman commentedComment #12
john.oltman commentedThanks Joel! I looked at your MR for the conflict module and it made me wonder why
$field_item_list->getValue()returned an empty array for a settings entity that should have had a host entity returned instead. So it's not clear to me yet that conflict is at fault. Let me experiment with this and see what I can find.Comment #13
john.oltman commentedThis is a bug in the
getValuemethod of theHostEntityItemclass. I have a fix but need to add some tests. Will post an MR as soon as I can.The getValue method is not used internally, so the flaw is only exposed if a different module calls it, as the
conflictmodule does.I'm going to re-title this issue so it is more clear where the problem lies.
Comment #14
john.oltman commentedComment #15
john.oltman commentedComment #16
joelpittet@john.oltman That's cool you came up with a solution here too. We were exploring fixes in
isEmpty()(which didn't make sense because it's changing state in a boolean check, no beuno) andreset()(mentioned in #9). Both solutions mitigated the error but didn't seem to get at the root of the problem. I did a whole bunch of logging to figure out where the empty array was happening, and seemed like a better fix in conflict because it could help other cases for computed fields. I will still explore that solution because I think the end result there will have a wider impact.Could you post the fix to
getValue()to the MR, I'd be happy review (because my head is deep in this problem)! I would love to see what you came up with.Comment #18
john.oltman commented@joelpittet I opened the MR on this issue. It's currently a one-liner. It will get bigger once I add tests for the affected class. With this fix in place, the conflict module works without any need for changes. As I mentioned in my post over there, a "wider impact" is not desirable because it could cause bugs in existing sites.
Comment #19
joelpittetI appreciate the review on the conflict issue and pointing that out. I will address that comment in that queue.
Thanks for posting the fix in !174, I still have my manual test up, so I will revert the conflict module patch and give it a step through! (edit: for once my inability to close FF tabs is a benefit)
Comment #21
john.oltman commentedComment #23
john.oltman commentedCommited to dev branch and will be in the next release. Granted credits. Thanks for catching this and for the help fixing @joelpittet!
Comment #24
joelpittet🙌 It was an interesting issue to take a dive into!