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

  1. Enable the registration and registration_waitlist modules.
  2. Create a host entity configured for registration (for example, an Event node using a registration type).
  3. Open its registration settings, set capacity to a non-zero value, and save.
  4. Edit the existing registration settings entity, increase capacity, and save.
  5. Observe a fatal error: Call to a member function getSetting() on null in RegistrationSettingsEventSubscriber::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.

CommentFileSizeAuthor
#5 Screenshot 2026-01-06 at 09.52.02.png619.84 KBjoelpittet
Command icon 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

joelpittet created an issue. See original summary.

john.oltman’s picture

Thanks @joel - can you clarify - does the Event node still exist, or was that deleted along the way.

joelpittet’s picture

Status: Active » Postponed (maintainer needs more info)

Sorry, still debugging trying to create a failing test, don't look behind the curtain :D

joelpittet’s picture

For 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.

joelpittet’s picture

StatusFileSize
new619.84 KB

Because a picture is worth a 💯 words, this was my migration D10 site, new Event node (not migrated), save of the capacity change:
Xdebug

joelpittet’s picture

Interesting 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();'

687 is my RegistrationSettings id for my new (un-migrated) event node "CS Lunch-Hour Art & Craft 2 - Electric boogaloo" and 15 was 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.

john.oltman’s picture

Thanks for digging into it - I'll try and reproduce on my test D10 system as well

joelpittet’s picture

The logs show the entity loads fine but HostEntityItem::ensureCalculated never logged, which implies the computed field isn’t being computed in the UI path. That points to RegistrationSettings::getHostEntity() using isEmpty() and short‑circuiting before the computed field calculates.

joelpittet’s picture

While 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() calling HostEntityFieldItemList->setValue([]) which then propagates to HostEntityItem->setValue([]) and wipes the computed entity.

Details:

  1. The trace points to conflict/src/Entity/ContentEntityConflictHandler.php:452autoMergeNonEditableFields() setting the list to empty.
  2. That call triggers registration/src/Plugin/Field/HostEntityFieldItemList.php:59 and then registration/src/Plugin/Field/FieldType/HostEntityItem.php to set the entity to NULL.
  3. After that, preSave() filters the item as empty, leaving the list empty and valueComputed = TRUE.

I am happy with whatever you'd like to do with this issue @john.oltman?

  1. Close works as designed?
  2. Mitigate by wiping out list in \Drupal\registration\Plugin\Field\HostEntityFieldItemList::reset() and setting $this->valueComputed back to false if it's empty.?
  3. Other thing on your mind?

I'll make an issue/stink over there and link back here for context

joelpittet’s picture

john.oltman’s picture

Assigned: Unassigned » john.oltman
Status: Postponed (maintainer needs more info) » Active
john.oltman’s picture

Thanks 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.

john.oltman’s picture

This is a bug in the getValue method of the HostEntityItem class. 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 conflict module does.

I'm going to re-title this issue so it is more clear where the problem lies.

john.oltman’s picture

Title: Waitlist: Saving registration settings with increased capacity fatals when host entity is missing » Saving registration settings fails when the conflict module is installed
Component: Registration Wait List » Registration Core
Issue summary: View changes
john.oltman’s picture

Issue summary: View changes
joelpittet’s picture

@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) and reset()(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.

john.oltman’s picture

@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.

joelpittet’s picture

I 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)

john.oltman’s picture

Assigned: john.oltman » Unassigned
Status: Active » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

john.oltman’s picture

Commited to dev branch and will be in the next release. Granted credits. Thanks for catching this and for the help fixing @joelpittet!

joelpittet’s picture

🙌 It was an interesting issue to take a dive into!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.