ssue Description:
Problem/Motivation
UI Suite Bootstrap theme uses class-based hooks with
\Drupal::service('class_resolver')->getInstanceFromDefinition() but Drupal themes are not included in
Composer's PSR-4 autoload map, causing fatal errors that completely break sites.
Steps to reproduce
1. Install UI Suite Bootstrap 5.2.0-beta2 on Drupal 11.2.2
2. Create a subtheme
3. Add any custom CSS or clear caches
4. Site crashes with: InvalidArgumentException: Class
"Drupal\ui_suite_bootstrap\HookHandler\PreprocessFormElement" does not exist
Error messages
The website encountered an unexpected error. Try again later.
InvalidArgumentException: Class "Drupal\ui_suite_bootstrap\HookHandler\LibraryInfoAlter" does not exist.
Root Cause
- Drupal themes are NOT included in Composer's PSR-4 autoload map (only modules are)
- The theme assumes autoloading will work for its classes in /src/ directory
- Some HookHandler classes extend others (e.g., PreprocessDetailsAccordion extends PreprocessFormElement)
- Parent classes must be loaded before child classes
- This is a fundamental architectural issue with using class-based hooks in themes
Proposed resolution
The theme should manually load its classes since PSR-4 autoloading is not available for themes. Add
explicit require_once statements at the beginning of ui_suite_bootstrap.theme.
Workaround
Add this code at the beginning of ui_suite_bootstrap.theme (after declare(strict_types=1);):
// CRITICAL AUTOLOAD FIX
// Themes don't get PSR-4 autoloading, must manually load classes
if (!class_exists('Drupal\ui_suite_bootstrap\HookHandler\PreprocessFormElement')) {
$theme_path = __DIR__;
// Load base classes first
$src_files = glob($theme_path . '/src/*.php');
if ($src_files) {
foreach ($src_files as $file) {
require_once $file;
}
}
// Load Utility classes
$utility_files = glob($theme_path . '/src/Utility/*.php');
if ($utility_files) {
foreach ($utility_files as $file) {
require_once $file;
}
}
// Load HookHandler parent classes first (in dependency order)
$parent_classes = [
'PreprocessFormElement.php',
'PreprocessLinksMediaLibraryMenu.php',
'PreprocessPage.php',
'PreprocessInput.php',
'PreprocessPager.php',
];
foreach ($parent_classes as $class_file) {
$file_path = $theme_path . '/src/HookHandler/' . $class_file;
if (file_exists($file_path)) {
require_once $file_path;
}
}
// Load remaining HookHandler classes
$handler_files = glob($theme_path . '/src/HookHandler/*.php');
if ($handler_files) {
foreach ($handler_files as $file) {
$basename = basename($file);
if (!in_array($basename, $parent_classes)) {
require_once $file;
}
}
}
}
For sites already affected
Sites can use composer patches to automatically apply this fix:
1. Install composer patches plugin:
composer require cweagans/composer-patches
2. Add to composer.json:
"extra": {
"patches": {
"drupal/ui_suite_bootstrap": {
"Fix autoload issue for class-based hooks": "patches/ui_suite_bootstrap-autoload-fix.patch"
}
}
}
3. Create the patch file with the above fix
Environment
- Drupal Version: 11.2.2
- PHP Version: 8.3
- Database: MySQL 8
- Web Server: nginx (DDEV)
Additional Information
This is a critical issue that makes sites completely unusable. The error can be triggered by:
- Any cache clear (drush cr)
- Adding custom CSS to a subtheme
- Modifying templates
- Sometimes just visiting the site
What DOESN'T fix it:
- composer dump-autoload (themes aren't in PSR-4 map)
- Reinstalling the theme (same architectural issue)
- Clearing caches (makes it worse)
This affects ALL sites using UI Suite Bootstrap with Drupal 11.
| Comment | File | Size | Author |
|---|---|---|---|
| #6 | ui_suite_bootstrap-autoload-fix-3540123.patch | 1.76 KB | aglobalwander_ |
| #5 | Capture d’écran du 2025-08-10 17-16-14.png | 192.65 KB | grimreaper |
Issue fork ui_suite_bootstrap-3540123
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
grimreaperHi,
I have been using this theme on all my projects during the last 2, 3 years and I have not encountered such problem.
Also using it on the 5.2.x branch with Core 11.2 and I didn't get the problem, also using it with sub-themes.
Can you please share your project composer.json to see its configuration?
I don't see MR or patch uploaded on this issue, which file is referenced here?
Note: I have not tested it yet, but I guess (or expect) new hooks declared with PHP Attribute to work in themes, and so it will remove this "HooHandler" workaround before OOP for hooks was introduced.
Comment #3
grimreaperMaybe related to #3490385: Fatal error on attempting to load a PHP class of the theme when switching the theme
Comment #4
aglobalwander_ commentedApologies posted response wrong issue.
Hi
# Response to UI Suite Bootstrap Issue #3540123
## composer.json excerpt
```json
{
"require": {
"drupal/ui_suite_bootstrap": "^5.2@beta",
"drupal/core": "^11.2",
"cweagans/composer-patches": "^1.7"
},
"extra": {
"patches": {
"drupal/ui_suite_bootstrap": {
"Fix autoload issue for class-based hooks": "patches/ui_suite_bootstrap-autoload-fix.patch"
}
}
}
}
```
## Environment Details
- **Drupal**: 11.2.2
- **PHP**: 8.3
- **UI Suite Bootstrap**: 5.2.0-beta2
- **Composer version**: 2.x
- **Local environment**: DDEV
- **Has subtheme**: Yes (sas_curriculum)
## How I Trigger the Issue
The error occurs consistently in my environment when:
1. Running `drush cr` after any template/CSS changes
2. Sometimes just visiting pages that use form elements
3. After deploying to staging/production
## The Patch That Fixed It
I'm attaching the patch file that completely resolves the issue. The patch adds manual class loading since themes don't get PSR-4 autoloading. This has been working stably for our production site.
## Possible Difference
The key difference might be:
- We have a custom subtheme with its own hook implementations
- We're using specific contrib modules that might interact differently
- Our composer autoload configuration might be different
## Testing Without the Patch
Without the patch, I get:
```
InvalidArgumentException: Class "Drupal\ui_suite_bootstrap\HookHandler\PreprocessFormElement" does not exist
```
With the patch applied, everything works perfectly.
## Note on PHP Attributes
You mentioned that new hooks with PHP Attributes might work better. That could be a good long-term solution, but for now, the manual loading approach is necessary for sites experiencing this issue.
Perhaps it only manifests under specific conditions.
I appreciate all the work done with this project it is great. I thought I wojld share this issue I ran into.
Comment #5
grimreaperThanks for the new infos.
I am sorry but there is still no file attached in the issue.
Do you have APCu enabled on your env? And in your composer.json do you have
"apcu-autoloader": true,configured.I dug into the class_loader service to see how it detects my classes locally as I do not have ui_suite_bootstrap obtained with Composer and it works on my environment.
I also have other local environments on DDEV, standard PHP config, and no
"apcu-autoloader": true,configured and ui_suite_bootstrap obtained with Composer and nothing related to it in vendor/composer/autoload_real.php or vendor/composer/autoload_classmap.php and it works too.Could you please share your PHP config and extensions, your Composer config, the list of contrib modules you are using and if you have patches applied?
Comment #6
aglobalwander_ commented# Response to UI Suite Bootstrap Issue #3540123
## Environment Details
```json
{
"drupal": "11.2.2",
"php": "8.3.23 (DDEV container)",
"ui_suite_bootstrap": "5.2.0-beta2",
"composer": "2.x",
"environment": "DDEV 1.23.x",
"database": "MySQL 8.0",
"web_server": "nginx",
"subtheme": "sas_curriculum (custom)"
}
```
## Composer Configuration
```json
{
"require": {
"drupal/core": "^11.2",
"drupal/ui_suite_bootstrap": "^5.2@beta",
"drupal/ui_patterns": "^2.0",
"drupal/ui_styles": "^1.7",
"drupal/gin": "^3.0@rc",
"cweagans/composer-patches": "^1.7"
},
"extra": {
"patches": {
"drupal/ui_suite_bootstrap": {
"Fix autoload issue for class-based hooks": "patches/ui_suite_bootstrap-autoload-fix-3540123.patch"
}
}
}
}
```
## How I Trigger the Issue
The error occurs consistently in my environment when:
1. **Running cache clear** after any template/CSS changes: `drush cr`
2. **Visiting pages with form elements** (uses PreprocessFormElement)
3. **After deployment** to staging/production environments
4. **When subtheme has custom hooks** that interact with parent theme
## Error Details
```
InvalidArgumentException: Class "Drupal\ui_suite_bootstrap\HookHandler\PreprocessFormElement" does not exist.
in Drupal\Core\DependencyInjection\ClassResolver->getInstanceFromDefinition()
(line 71 of core/lib/Drupal/Core/DependencyInjection/ClassResolver.php).
```
## Root Cause Analysis
The issue stems from the fundamental architecture difference between modules and themes in Drupal:
1. **Modules get PSR-4 autoloading** via Composer's autoload map
2. **Themes do NOT get PSR-4 autoloading** - they're not included in vendor/composer/autoload_psr4.php
3. UI Suite Bootstrap uses `\Drupal::service('class_resolver')->getInstanceFromDefinition()` which relies on autoloading
4. Some HookHandler classes extend others (inheritance dependencies)
5. Without autoloading, classes must be manually loaded in correct order
## The Fix (Patch Attached)
I'm attaching the patch file `ui_suite_bootstrap-autoload-fix-3540123.patch` that completely resolves the issue. The patch adds manual class loading at the beginning of `ui_suite_bootstrap.theme` to ensure all classes are available before they're used.
## Testing Without the Patch
```bash
# Clear caches - triggers the error
ddev drush cr
# Result:
InvalidArgumentException: Class "Drupal\ui_suite_bootstrap\HookHandler\PreprocessFormElement" does not exist
```
## Testing With the Patch
```bash
# Apply patch
composer install
# Clear caches - works perfectly
ddev drush cr
# Site loads normally
ddev drush status
# Bootstrap: Successful
```
## APCu Configuration
Responding to your question about APCu:
```bash
# Check APCu status in DDEV
ddev exec php -m | grep -i apc
# Output: apcu
# Check composer.json
grep -i apcu composer.json
# No "apcu-autoloader" configuration found
```
I do have APCu enabled in DDEV (standard configuration) but no special composer configuration for it.
## Contrib Modules Installed
Key modules that might interact with theming:
- gin (admin theme)
- ui_patterns
- ui_patterns_settings
- ui_styles
- components
- twig_tweak
- entity_browser
- field_group
- layout_builder
- media_library
## Why This Might Not Affect Everyone
I suspect the issue manifests under specific conditions:
1. **Subthemes with custom hooks** - Our subtheme has extensive hook implementations
2. **Specific cache clear patterns** - The issue appears most often after cache rebuilds
3. **Module interactions** - Certain contrib modules might trigger the class loading earlier
4. **Deployment differences** - Production environments might have different opcache/autoload settings
any insight on what to check here would be helpful too.
## Proposed Long-term Solutions
1. **Immediate**: Apply this patch to ensure classes are loaded
2. **Better**: Convert to PHP Attributes for hooks (as you mentioned)
3. **Best**: Have Composer include themes in PSR-4 autoload map
## Note on the Patch
The patch is minimal and safe - it simply ensures classes exist before they're used. It has no performance impact as the `class_exists()` check prevents redundant loading.
Thank you for maintaining this excellent theme! It's been crucial for our Bootstrap 5 implementation. I hope this information helps identify why some users experience this issue while others don't.
Best regards,
Scott (aglobalwander_)
Comment #7
grimreaperSadly, no OOP hooks for theme yet https://drupal.slack.com/archives/C1BMUQ9U6/p1755522211129779
Need to wait.
Comment #8
herved commentedHi, just to report that we're also facing this issue with DDEV. I think the issue is valid, but I haven’t yet investigated what’s going on exactly.
Indeed, themes don’t get PSR-4 autoloading, but these classes are invoked using
ClassResolver::getInstanceFromDefinition, so should get loaded if not already?Also, I wonder if this is specific to APCu — does disabling APCu resolve it? Just to confirm.
I don't know much about autoloading but maybe registering the namespace in composer autoload might be a better workaround for now?
I'll do some testing/investigation and update.
Comment #9
herved commentedUpdate: registering the namespace manually in composer.json does seem to work.
Still a workaround of course, but better than the proposed patch.
The one for my_subtheme is only needed if you implement hook classes similar to ui_suite_bootstrap obviously.
Make sure to
composer dump-autoloadafter that.Comment #10
grimreaperThanks @herved for the investigation.
Good idea the autoload in the composer.json! (this reminds me of a bug in a custom project (with normal layout plugins as PHP in a theme as it can be registered in theme))
I will try to propose an MR next week or you can if you want.
And it is strange because I have projects using DDEV and ui_suite_bootstrap and didn't get the bug.
Comment #11
herved commentedSo far I was not able to reproduce on a clean ui_suite_bootstrap ddev setup, sadly.
But it looks like some race condition.
I could only reproduce it on my project and it happens intermittently. This seems to involve the main request + aggregated assets (CSS/JS) requests (needs aggregation enabled).
When that happens,
\Composer\Autoload\ClassLoader::findFilegets called on $classDrupal\ui_suite_bootstrap\HookHandler\LibraryInfoAlterwhile somehow themes are not yet psr4-registered ($this->prefixDirsPsr4doesn't contain any themes namespaces), sofindFileWithExtensionreturnsfalseand gets stored inapcu_add(). At this point, the only way to recover is to restart ddev or the web server which I assume clears the apcu cache.Here is a stacktrace and method I used: https://gist.github.com/vever001/009e4163eb6d27cab26a2b5a0df41a62
That request is a CSS aggregated URI (/sites/default/files/css/...).
I wonder precisely why they are not psr4-registered yet in such cases, because IIUC this should happen earlier in the request, in
ThemeHandler::addThemecalled very early on KernelEvents::REQUEST.Update: It appears
ThemeHandler::addThemeisn't called in such cases, which explains why themes aren't psr4-registered. Why it's not called is yet to be determined...Comment #12
herved commentedI managed to reproduce on a clean setup! though using xdebug to manipulate the execution order.
- Install clean ui_suite_bootstrap with ddev (enable modules + theme)
- Load 1 tab with homepage and another tab with the first aggregated CSS URL on the homepage (sites/default/files/css/...)
-
ddev drush cr && ddev xdebug on(clears cache, starts xdebug and clears APCu cache)- Place a breakpoint on first line in
\Composer\Autoload\ClassLoader::findFilewith condition:$class === 'Drupal\ui_suite_bootstrap\HookHandler\LibraryInfoAlter'- Now run 2 concurrent requests:
-- First load the homepage, let it hit the breakpoint and pause.
-- Then load the CSS URL page, let it hit the breakpoint as well, step over a bit and notice that it cannot find the class and will store false in
apcu_add()then let it resume.- At this point the apcu cache is corrupted. All pages are throwing
The only way to recover is to clear APCu (e.g. via ddev restart or ddev xdebug toggle)
Maybe there are easier ways to trigger this, but this is so far one reliable way I found.
I didn't dig much further but I suggest to just register the namespace in composer as per #9.
Also, subthemes (and so starterkits) may have to do the same if they also use the same "class-based hooks".
Comment #13
grimreaperThanks @herved for your investigation.
Need also to document it.
Comment #15
grimreaperIf you can give a quick review before merge that will be great! :)
Comment #16
herved commentedLeft a small non-blocking comment.
Works perfectly on my side — Many thanks for the excellent support, and thanks to the entire team behind the UI initiative!
Comment #19
grimreaperMerged.
Comment #21
grimreaper@aglobalwander_ , @herved
If no more autoload problem with the current dev version, I will do a release.
Can you both confirm that please?
Comment #22
herved commentedI'm currently on 5.2.0-beta3 with the fix from #9 in my main composer.json, no more issues since then.
But I tested the fix on current dev with procedure from #12 and can confirm it does solve the issue.
So +1 for me.
Comment #23
grimreaperThanks! Waiting for @aglobalwander_ feedback as well.
Comment #24
grimreaperFun fact....
While testing #3373929: CSS and JS returns 404 when enabling css and js aggregation on nginx on ddev to have a quick nginx setup, I reproduced the issue...
InvalidArgumentException: Class "Drupal\ui_suite_bootstrap\HookHandler\LibraryInfoAlter" does not exist. in Drupal\Core\DependencyInjection\ClassResolver->getInstanceFromDefinition() (line 32 of /var/www/html/app/core/lib/Drupal/Core/DependencyInjection/ClassResolver.php).
https://sobki-platform-demo-bootstrap.ddev.site/sites/default/files/css/...
And so confirm that also need to add autoload in Sobki Bootstrap and that I will do a release because I witness the fix too!