PHP 8 TypeError in buildOptionsForm(): TranslatableMarkup used as array key for breakpoint optgroups

Created on 22 September 2025, 26 days ago

Problem/Motivation

On PHP 8.x, visiting a View’s Exposed form settings and enabling Better Exposed Filters can trigger a TypeError when the Breakpoint module is enabled. The error is caused by using a TranslatableMarkup object as an array key while building the “Breakpoint autosubmit” select options. In PHP 8, array keys must be strings or ints; using an object (TranslatableMarkup) as an array offset results in a fatal TypeError.

TypeError: Cannot access offset of type Drupal\Core\StringTranslation\TranslatableMarkup on array in Drupal\better_exposed_filters\Plugin\views\exposed_form\BetterExposedFilters->buildOptionsForm() (line 258 of /var/www/html/modules/contrib/better_exposed_filters/src/Plugin/views/exposed_form/BetterExposedFilters.php).

Backtrace
#0 /var/www/html/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php(1833): Drupal\better_exposed_filters\Plugin\views\exposed_form\BetterExposedFilters->buildOptionsForm()
#1 /var/www/html/core/modules/views/src/Plugin/views/display/PathPluginBase.php(438): Drupal\views\Plugin\views\display\DisplayPluginBase->buildOptionsForm()
#2 /var/www/html/core/modules/views/src/Plugin/views/display/Page.php(279): Drupal\views\Plugin\views\display\PathPluginBase->buildOptionsForm()
#3 /var/www/html/core/modules/views_ui/src/Form/Ajax/Display.php(74): Drupal\views\Plugin\views\display\Page->buildOptionsForm()
#4 [internal function]: Drupal\views_ui\Form\Ajax\Display->buildForm()
#5 /var/www/html/core/lib/Drupal/Core/Form/FormBuilder.php(528): call_user_func_array()
#6 /var/www/html/core/lib/Drupal/Core/Form/FormBuilder.php(279): Drupal\Core\Form\FormBuilder->retrieveForm()
#7 /var/www/html/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php(215): Drupal\Core\Form\FormBuilder->buildForm()
#8 /var/www/html/core/lib/Drupal/Core/Render/Renderer.php(593): Drupal\views_ui\Form\Ajax\ViewsFormBase->Drupal\views_ui\Form\Ajax\{closure}()
#9 /var/www/html/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php(217): Drupal\Core\Render\Renderer->executeInRenderContext()
#10 /var/www/html/core/modules/views_ui/src/Form/Ajax/ViewsFormBase.php(150): Drupal\views_ui\Form\Ajax\ViewsFormBase->ajaxFormWrapper()
#11 /var/www/html/core/modules/views_ui/src/Form/Ajax/Display.php(46): Drupal\views_ui\Form\Ajax\ViewsFormBase->getForm()
#12 [internal function]: Drupal\views_ui\Form\Ajax\Display->getForm()
#13 /var/www/html/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array()
#14 /var/www/html/core/lib/Drupal/Core/Render/Renderer.php(593): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#15 /var/www/html/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(121): Drupal\Core\Render\Renderer->executeInRenderContext()
#16 /var/www/html/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext()
#17 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(183): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#18 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw()
#19 /var/www/html/core/lib/Drupal/Core/StackMiddleware/Session.php(53): Symfony\Component\HttpKernel\HttpKernel->handle()
#20 /var/www/html/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
#21 /var/www/html/core/lib/Drupal/Core/StackMiddleware/ContentLength.php(28): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
#22 /var/www/html/core/modules/big_pipe/src/StackMiddleware/ContentLength.php(32): Drupal\Core\StackMiddleware\ContentLength->handle()
#23 /var/www/html/core/modules/page_cache/src/StackMiddleware/PageCache.php(116): Drupal\big_pipe\StackMiddleware\ContentLength->handle()
#24 /var/www/html/core/modules/page_cache/src/StackMiddleware/PageCache.php(90): Drupal\page_cache\StackMiddleware\PageCache->pass()
#25 /var/www/html/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\page_cache\StackMiddleware\PageCache->handle()
#26 /var/www/html/modules/contrib/tracer/src/StackMiddleware/TracesMiddleware.php(38): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
#27 /var/www/html/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\tracer\StackMiddleware\TracesMiddleware->handle()
#28 /var/www/html/core/lib/Drupal/Core/StackMiddleware/AjaxPageState.php(36): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
#29 /var/www/html/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\Core\StackMiddleware\AjaxPageState->handle()
#30 /var/www/html/core/lib/Drupal/Core/DrupalKernel.php(709): Drupal\Core\StackMiddleware\StackedHttpKernel->handle()
#31 /var/www/html/index.php(19): Drupal\Core\DrupalKernel->handle()
#32 {main}

Steps to reproduce

1. Ensure the Breakpoint core module is enabled and has breakpoint groups defined (Bootstrap5 theme triggers the issue for me).
2. Create or edit a View that uses “Better Exposed Filters” as the Exposed form plugin.

Proposed resolution

Explicitly cast TranslatableMarkup to string before using as an array key, and initialize string-only defaults.

// Initialize with a string default.
$breakpoints = ['' => (string) $this->t('-Any-')];

$autosubmit_breakpoint_description = $this->t('Breakpoint to determinate whether auto-submit should be enabled for the current screen dimensions.');
if ($this->breakpointManager instanceof BreakpointManagerInterface) {
  foreach ($this->breakpointManager->getGroups() as $group => $group_label) {
    // Cast label to string for use as array key (PHP 8 requirement).
    <strong>$group_label_str = (string) $group_label;</strong>
    $group_breakpoints = $this->breakpointManager->getBreakpointsByGroup($group);
    /** @var \Drupal\breakpoint\Breakpoint $breakpoint */
    foreach ($group_breakpoints as $breakpoint_id => $breakpoint) {
      // Value can remain TranslatableMarkup, but casting to string is harmless:
      $breakpoints[<strong>$group_label_str</strong>]["$group:$breakpoint_id"] = (string) $breakpoint->getLabel();
    }
  }
}
else {
  $autosubmit_breakpoint_description .= ' ' . $this->t('Enable the Breakpoint Module if you want to limit auto-submit feature only for specific device dimensions.');
}
🐛 Bug report
Status

Active

Version

7.1

Component

Code

Created by

🇬🇧United Kingdom joehuggans Harrogate, UK

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024