Problem/Motivation

Short video showing the problem: https://www.youtube.com/watch?v=NNC7vLwjswA

Steps to reproduce

  1. Clean install Drupal
  2. Install Admin
  3. Enable it as admin theme
  4. JS is now broken (see console + navigation doesn't work)

Note that clearing cache does not fix the issue, but disabling aggregation does fix the issue.

Errors below:

Note that the first file a 404. That has to be the root cause.

js_Br68L5jck8RMhQvkt…za2J-Nf8Z-KvCY.js:1 
 Failed to load resource: the server responded with a status of 400 ()
appearance:1 Refused to execute script from 'https://drupal-admin.ddev.site/sites/default/files/js/js_Br68L5jck8RMhQvktz…uage=en&theme=default_admin&libraries=eJxLzi9K1U8pKi1IzAlOLSnJzEsvBgBLhwey' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.

js_AIv6U2Md9_sRSnZbZ…LEnP0MkpyKwCbYwrR:4 Uncaught ReferenceError: drupalSettings is not defined
    at js_AIv6U2Md9_sRSnZbZ…MkpyKwCbYwrR:4:1255
js_SHbVJ_ww_2CqgPwyB…8gsSNVPgjIAO9cGrg:2 Uncaught ReferenceError: drupalSettings is not defined
    at js_SHbVJ_ww_2CqgPwyB…VPgjIAO9cGrg:2:1326
js_qWeh8V-sd8v4VBId4…Vcl_M9ugnjdUfQ9og:2 Uncaught ReferenceError: drupalSettings is not defined
    at js_qWeh8V-sd8v4VBId4…9ugnjdUfQ9og:2:6740

Watchdog is showing the following error:

Type	client error
Date	Wednesday, 5 August 2026 - 08:40
User	admin
Location	https://drupal-admin.ddev.site/sites/default/files/js/js_Br68L5jck8RMhQvktzTv3SEbkgMaOza2J-Nf8Z-KvCY.js?language=en&libraries=eJxLzi9K1U8pKi1IzAlOLSnJzEsvBgBLhwey&scope=header&theme=default_admin
Referrer	https://drupal-admin.ddev.site/admin/appearance
Message	Symfony\Component\HttpKernel\Exception\BadRequestHttpException: Invalid filename. in Drupal\system\Controller\AssetControllerBase->getGroup() (line 245 of /var/www/html/core/modules/system/src/Controller/AssetControllerBase.php).
Severity	Warning
Hostname	172.18.0.5
Operations	

I had Claude (Fable) troubleshoot, and it's indicating a core aggregation bug:

From Claude:

Diagnosis

The failing request is the header-scope aggregate for exactly one library, core/drupalSettings. I decoded the compressed libraries= query parameter.

The controller returns the 400 response from getGroup() because it resolves that library to zero header assets, so there is no group at delta 0 to serve.

The causal chain is:

  1. default_admin/init is declared with header: true and depends on core/drupalSettings in default_admin.libraries.yml:349.

    Contrib Gin has the identical gin_init pattern, which explains why only these two themes reproduce the issue. Olivero and Stark have no header-scoped libraries, so drupalSettingsLoader.js remains in the footer and everything works.

  2. During page rendering, AssetResolver::getJsAssets() expands header libraries with their dependencies in AssetResolver.php:390, so core/drupalSettings is pulled into the header.

    Its loader file becomes its own aggregate group. Because the group maps one-to-one to a library, JsCollectionOptimizerLazy::optimize() takes the new fast path at JsCollectionOptimizerLazy.php:139.

    The generated URL contains:

    ?scope=header&libraries=core/drupalSettings

    rather than the full include, exclude, and delta context.

  3. When the browser requests that URL, JsAssetController::getGroups() re-resolves only core/drupalSettings, without its dependents.

    Header placement is computed solely from the header flag on the libraries being resolved in AssetResolver.php:353-358. However, core/drupalSettings does not itself declare header: true.

    Its header placement during the original render came entirely from default_admin/init, which is absent from the regeneration request.

    As a result:

    • The loader resolves to the footer.
    • The header asset set is empty.
    • getGroup([], 0) throws BadRequestHttpException('Invalid filename.').
    • The request returns a 400 response with a text/plain content type.
    • drupalSettings is not defined errors cascade throughout the page.

I confirmed this with a Drush simulation:

  • Resolving core/drupalSettings by itself places the loader in the footer.
  • Resolving it through default_admin/init, with dependencies, places it in the header.

This also explains the behavior described in comment #8. deliver() serves the file directly when it already exists on disk, as seen in AssetControllerBase.php:120. Therefore, manually creating the file works.

The hash remains deterministic because it is an HMAC of the aggregate group contents.

In summary, the libraries= aggregate URL fast path, introduced as part of the newer aggregate_target work on the main branch, is not safe for header-scope groups whose libraries are present in the header only transitively. The generated URL does not contain enough context to reproduce the original scope.

Fix options

  • Controller-side fix (recommended):

    In JsAssetController::getGroups(), when processing a libraries= request, trust the requested scope query parameter instead of recomputing the scope exclusively from the library definitions.

    The URL already asserts that these libraries formed a single group in that scope. This approach would also repair already-cached HTML that points to the broken URL.

    One complication is that each item's scope contributes to the hash. The item scopes must therefore be changed to the requested scope before hashing; otherwise, the request could enter a redirect loop.

  • URL-generation fix:

    In JsCollectionOptimizerLazy, skip the libraries= shortcut and fall back to the include-and-delta URL when both of the following are true:

    • The aggregate group is in the header scope.
    • None of the group's libraries independently declare header: true.

    In other words, the shortcut should not be used when the group's scope cannot be reproduced by resolving its libraries independently.

Proposed next step

I can write the core patch and a regression test for the controller-side fix.

Issue fork drupal-3614911

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

mherchel created an issue. See original summary.

cilefen’s picture

Can we get the browser console errors in the issue summary instead of only in a video?

mherchel’s picture

Issue summary: View changes

Ha. Thanks for asking. Added to the issue summary.

It looks like the root cause is the first aggregated JS file going 404.

Can anyone else reproduce? Is this a local problem for me?

jurgenhaas’s picture

I can't reproduce this, neither on main nor on 11.4. But I've seen DDEV-specific caching issues in other contexts recently as well. People reported that a DDEV restart (or re-init?) fixed such stuff for them.

mherchel’s picture

Thanks for the info.

Still no luck

  1. I upgraded ddev to the latest
  2. Did a ddev delete -O and ddev config

Still no luck

I also tried other themes.

  • I'm unable to reproduce the issue with either Olivero or Stark
  • I was able to reproduce the issue with Gin (contrib)

I'm going to ask around on Slack to see if others can reproduce.

cilefen’s picture

Does Drupal log anything?

mherchel’s picture

Issue summary: View changes

Good question. Watchdog is showing the following error:

Type	client error
Date	Wednesday, 5 August 2026 - 08:40
User	admin
Location	https://drupal-admin.ddev.site/sites/default/files/js/js_Br68L5jck8RMhQvktzTv3SEbkgMaOza2J-Nf8Z-KvCY.js?language=en&libraries=eJxLzi9K1U8pKi1IzAlOLSnJzEsvBgBLhwey&scope=header&theme=default_admin
Referrer	https://drupal-admin.ddev.site/admin/appearance
Message	Symfony\Component\HttpKernel\Exception\BadRequestHttpException: Invalid filename. in Drupal\system\Controller\AssetControllerBase->getGroup() (line 245 of /var/www/html/core/modules/system/src/Controller/AssetControllerBase.php).
Severity	Warning
Hostname	172.18.0.5
Operations	
mherchel’s picture

Some additional troubleshooting.

  • Going to the URL (https://drupal-admin.ddev.site/sites/default/files/js/js_Br68L5jck8RMhQvktzTv3SEbkgMaOza2J-Nf8Z-KvCY.js?scope=header&language=en&theme=default_admin&libraries=eJxLzi9K1U8pKi1IzAlOLSnJzEsvBgBLhwey) causes a "Invalid filename." message in the browser (not sure if this is Drupal or the web server).
  • The js_Br68L5jck8RMhQvktzTv3SEbkgMaOza2J-Nf8Z-KvCY.js file does not exist
  • If I manually create the file, the file will load as expected (which means the filename format works just fine).
  • The filename does not change when I do a drush si. I expected the filenames to be random.
bernardm28’s picture

I can confirm i get this issue on the main branch and on https://www.drupal.org/project/drupal/issues/3606571#comment-16719685
https://www.drupal.org/files/issues/2026-08-05/Screenshot%202026-08-05%2...

A good way of testing this issue is going to /admin/structure/menu. The chevrons are missing on the operations edit buttons and it throws a console error.

missing chevrons

The error that it gives me when aggregation is on.

Uncaught ReferenceError: drupalSettings is not defined
    at js_1dF6Mh9GvTVkJTBBCP1paeYTVN-JV5zTEQdjl8ivqaY.js?scope=footer&language=en&theme=default_admin&libraries=eJxLzi9K1c_JT0zJKtZJBrFTikoLEnP0MkpyKwCbYwrR:4:1255
js_LnBtFYOj5NfP8x5BvJjY2zy-H9PFWvDUh_PL5byfn4M.js?scope=footer&language=en&theme=default_admin&libraries=eJxLykyPL8gsSNVPgjIAO9cGrg:2 Uncaught ReferenceError: drupalSettings is not defined
    at js_LnBtFYOj5NfP8x5BvJjY2zy-H9PFWvDUh_PL5byfn4M.js?scope=footer&language=en&theme=default_admin&libraries=eJxLykyPL8gsSNVPgjIAO9cGrg:2:1326
js_DM9n59Vhx1-DPvrJaRnVYqRlE-LKqJEKgXm0eDqBCFY.js?scope=footer&language=en&theme=default_admin&libraries=eJxLzs8rSa0oKU3M0U8pKi1IzNFLhovo5mTmZRfrJOcXpcIkE5NLMstSwRIo4gVF-elFqcXFAOCzHwI:2 Uncaught ReferenceError: drupalSettings is not defined
    at js_DM9n59Vhx1-DPvrJaRnVYqRlE-LKqJEKgXm0eDqBCFY.js?scope=footer&language=en&theme=default_admin&libraries=eJxLzs8rSa0oKU3M0U8pKi1IzNFLhovo5mTmZRfrJOcXpcIkE5NLMstSwRIo4gVF-elFqcXFAOCzHwI:2:6740
js_1e6PW4sXdKfOxbrajBZ45zGz02RUlQNHSYbJMfT50r0.js?scope=footer&language=en&theme=default_admin&libraries=eJxtzmEOgzAIBeALGT2SQcoMrqMMqJm3n4tb4hp_8vHyAIvRkKwq5B4WeHX4AZYgk52WZyXbxsqHf4OJXTMg_eER7bU4BxfpEt2g5hghPVgGQCSJpgVymS_o9MjPrehUI_baMwdMmYxciziv1JwkR1A6hmYlsPIMF296MN63NxSVa4o:2 Uncaught ReferenceError: drupalSettings is not defined
    at js_1e6PW4sXdKfOxbrajBZ45zGz02RUlQNHSYbJMfT50r0.js?scope=footer&language=en&theme=default_admin&libraries=eJxtzmEOgzAIBeALGT2SQcoMrqMMqJm3n4tb4hp_8vHyAIvRkKwq5B4WeHX4AZYgk52WZyXbxsqHf4OJXTMg_eER7bU4BxfpEt2g5hghPVgGQCSJpgVymS_o9MjPrehUI_baMwdMmYxciziv1JwkR1A6hmYlsPIMF296MN63NxSVa4o:2:19455
js_1jRH8QsOCn68JOJjtI6RyJOkufMvJ3cq56en7mVRq44.js?scope=footer&language=en&theme=default_admin&libraries=eJxLzi9K1U8pKi1IzAEAGfkEYQ:2 Uncaught TypeError: Drupal.displace is not a function
    at initDisplace (js_P4YdJzuKD82kzPDAsChRH0C1Dcckr1Jg7yleHAxsuto.js?scope=footer&language=en&theme=default_admin&libraries=eJxtyksKwEAIBNEL5XMmYcwgSLc4Mrl-ltm4rVeQbVPKiNtQmhC_RjIGXxxosEgvi9aCwa3Z2pJHz0oTTNf2-NsHW_I7GA:10:2115)
    at Array.forEach (<anonymous>)
    at Object.attach (js_P4YdJzuKD82kzPDAsChRH0C1Dcckr1Jg7yleHAxsuto.js?scope=footer&language=en&theme=default_admin&libraries=eJxtyksKwEAIBNEL5XMmYcwgSLc4Mrl-ltm4rVeQbVPKiNtQmhC_RjIGXxxosEgvi9aCwa3Z2pJHz0oTTNf2-NsHW_I7GA:10:2255)
    at js_1jRH8QsOCn68JOJjtI6RyJOkufMvJ3cq56en7mVRq44.js?scope=footer&language=en&theme=default_admin&libraries=eJxLzi9K1U8pKi1IzAEAGfkEYQ:2:427
    at Array.forEach (<anonymous>)
    at Drupal.attachBehaviors (js_1jRH8QsOCn68JOJjtI6RyJOkufMvJ3cq56en7mVRq44.js?scope=footer&language=en&theme=default_admin&libraries=eJxLzi9K1U8pKi1IzAEAGfkEYQ:2:353)
    at js_1jRH8QsOCn68JOJjtI6RyJOkufMvJ3cq56en7mVRq44.js?scope=footer&language=en&theme=default_admin&libraries=eJxLzi9K1U8pKi1IzAEAGfkEYQ:3:373
    at HTMLDocument.listener (js_1jRH8QsOCn68JOJjtI6RyJOkufMvJ3cq56en7mVRq44.js?scope=footer&language=en&theme=default_admin&libraries=eJxLzi9K1U8pKi1IzAEAGfkEYQ:3:161)
cilefen’s picture

They are hashes, so not random. #3589208: Always use the file contents to determine asset aggregate filename hashes

You should experiment by disabling asset aggregation to verify that the asset system is the immediate problem.

cilefen’s picture

Oh, you did say in the issue summary that disabling aggregation resolves this. Anyway, no, they are not random.

mherchel’s picture

I had Claude (Fable) troubleshoot, and it's indicating a core aggregation bug:

From Claude:

Diagnosis

The failing request is the header-scope aggregate for exactly one library, core/drupalSettings. I decoded the compressed libraries= query parameter.

The controller returns the 400 response from getGroup() because it resolves that library to zero header assets, so there is no group at delta 0 to serve.

The causal chain is:

  1. default_admin/init is declared with header: true and depends on core/drupalSettings in default_admin.libraries.yml:349.

    Contrib Gin has the identical gin_init pattern, which explains why only these two themes reproduce the issue. Olivero and Stark have no header-scoped libraries, so drupalSettingsLoader.js remains in the footer and everything works.

  2. During page rendering, AssetResolver::getJsAssets() expands header libraries with their dependencies in AssetResolver.php:390, so core/drupalSettings is pulled into the header.

    Its loader file becomes its own aggregate group. Because the group maps one-to-one to a library, JsCollectionOptimizerLazy::optimize() takes the new fast path at JsCollectionOptimizerLazy.php:139.

    The generated URL contains:

    ?scope=header&amp;libraries=core/drupalSettings

    rather than the full include, exclude, and delta context.

  3. When the browser requests that URL, JsAssetController::getGroups() re-resolves only core/drupalSettings, without its dependents.

    Header placement is computed solely from the header flag on the libraries being resolved in AssetResolver.php:353-358. However, core/drupalSettings does not itself declare header: true.

    Its header placement during the original render came entirely from default_admin/init, which is absent from the regeneration request.

    As a result:

    • The loader resolves to the footer.
    • The header asset set is empty.
    • getGroup([], 0) throws BadRequestHttpException('Invalid filename.').
    • The request returns a 400 response with a text/plain content type.
    • drupalSettings is not defined errors cascade throughout the page.

I confirmed this with a Drush simulation:

  • Resolving core/drupalSettings by itself places the loader in the footer.
  • Resolving it through default_admin/init, with dependencies, places it in the header.

This also explains the behavior described in comment #8. deliver() serves the file directly when it already exists on disk, as seen in AssetControllerBase.php:120. Therefore, manually creating the file works.

The hash remains deterministic because it is an HMAC of the aggregate group contents.

In summary, the libraries= aggregate URL fast path, introduced as part of the newer aggregate_target work on the main branch, is not safe for header-scope groups whose libraries are present in the header only transitively. The generated URL does not contain enough context to reproduce the original scope.

Fix options

  • Controller-side fix (recommended):

    In JsAssetController::getGroups(), when processing a libraries= request, trust the requested scope query parameter instead of recomputing the scope exclusively from the library definitions.

    The URL already asserts that these libraries formed a single group in that scope. This approach would also repair already-cached HTML that points to the broken URL.

    One complication is that each item's scope contributes to the hash. The item scopes must therefore be changed to the requested scope before hashing; otherwise, the request could enter a redirect loop.

  • URL-generation fix:

    In JsCollectionOptimizerLazy, skip the libraries= shortcut and fall back to the include-and-delta URL when both of the following are true:

    • The aggregate group is in the header scope.
    • None of the group's libraries independently declare header: true.

    In other words, the shortcut should not be used when the group's scope cannot be reproduced by resolving its libraries independently.

Proposed next step

I can write the core patch and a regression test for the controller-side fix.

mherchel’s picture

I'm currently having Claude write a patch and will verify it solves the issue.

I know @catch has been doing perf work involving aggregation lately. Will ping him in Slack when ready.

bernardm28’s picture

Disabling aggregation solves the issue i can confirm that.
It seems that specifically the Aggregate JavaScript files has the issue.
If i turn that off the chevrons come back and the site seems to work as expected.

jurgenhaas’s picture

Confirmed. I also missed the part about aggregation being part of the issue in the IS.

Now I can reproduce the issue as well when enabling JS aggregation. But only on main, not on 11.4

mherchel’s picture

I had Claude (Fable) write the code in the MR. Although I can't speak for the code quality, I can verify that it does resolve the issue.

Here's what Claude had to say about this:

What the patch contains

  1. The fixcore/modules/system/src/Controller/JsAssetController.php.

    For ?libraries= aggregate requests, getGroups() no longer trusts the recomputed header/footer split. A library such as core/drupalSettings only appears in the header transitively (via default_admin/init's header: true), and that page context is unavailable when the controller re-resolves the library on its own.

    Instead, the controller:

    • Merges both the resolved header and footer scopes.
    • Re-sorts the assets with AssetResolver::sort() to restore the original render-time order.
    • Stamps each asset with the scope provided in the request URL.

    This ensures the generated hash matches the render-time hash exactly, allowing the aggregate to be served successfully and written to disk.

  2. Regression test — a new header_assets_test test module.

    The module defines a header: true library that depends on core/drupal (and therefore core/drupalSettings) and attaches it to every page using hook_page_attachments().

    It is wired into AssetOptimizationTest with an assertion verifying that the page generates a header aggregate for transitively-header libraries. The same coverage also applies to AssetOptimizationUmamiTest, which inherits from it.

Validation

  • With the fix reverted, the regression test fails with the exact signature of this bug:
    Current response status code is 400, but 200 expected.

    on the generated header aggregate.

  • With the fix applied, the full test suite passes (245 assertions), including the hash-mismatch redirect assertions, confirming there are no redirect loops.
  • On the reproduced DDEV site, the previously failing js_Br68… aggregate URL now returns 200 text/javascript, is written to disk successfully, and both /admin/content and /admin/modules load without any JavaScript console errors.
  • commit-code-check.sh passes, including:
    • CSpell
    • PHPStan
    • PHPCS
    • ESLint

Caveats

  • The Brotli/Gzip compression assertions are environment-sensitive. Your local DDEV Nginx instance does not include the Brotli module, so assertBrotli() fails locally regardless of this patch. Drupal core CI passes these assertions as expected.
  • To reproduce the multi-library case, I temporarily enabled extension_discovery_scan_tests and the header_assets_test module on your development site. Those changes have since been reverted, and the site is back to its original olivero/default_admin configuration.
mherchel’s picture

Issue summary: View changes

Updating IS.

mherchel’s picture

Priority: Normal » Major
Status: Active » Needs review

Setting this to Major since it breaks what will become Drupal's default Admin theme.

mherchel’s picture

Component: Admin theme » aggregator.module
mherchel’s picture

Component: aggregator.module » asset library system
jurgenhaas’s picture

This is looking good. I've tested the failing scenario locally, and the bug is gone away.

I've reviewed the code in core/modules/system/src/Controller/JsAssetController.php and it looks correct, although I have to admit that I'm not an asset aggregation expert and don't know if this would have any unintended side-effects. But it looks as if it just closes a gap and that shouldn't cause any harm.

But I leave it at NR for others to also have a look.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new979 bytes

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

mherchel’s picture

From @catch in Slack https://drupal.slack.com/archives/C079NQPQUEN/p1785941457459889?thread_t...

If the controller fix is correct, that's the better way to fix it because using ?libraries results in much better browser/CDN cache hit rates. It seems like it probably ought to be OK because if it's in the header with another library, it's in the header, it's not going to suddenly move unless the library definitions change.

We should try to get rid of header javascript in default_admin though, separate issue of course.
[10:53 AM]Pretty late here so can't do a proper code review (and out most of tomorrow and the day after too)

mherchel’s picture

Title: JS gets broken when enabling default_admin on clean install » JS aggregation returns 400 for libraries loaded in the header only as dependencies

Fixing my bad grammar title with something more descriptive.

catch’s picture

Title: JS aggregation returns 400 for libraries loaded in the header only as dependencies » JS gets broken when enabling default_admin on clean install
Component: asset library system » Admin theme
Priority: Major » Normal
Status: Needs work » Active

Don't have time for an in-depth review today, but overall I think that the diagnosis is probably correct here but not overly keen on either of the suggested fixes, from the inline comment:

 // A 'libraries' query argument means the aggregate contains every JS
      // asset of the listed libraries, all in the same scope. Whether an asset
      // is resolved to the header or the footer depends on the full set of
      // libraries attached to the page it was rendered on: a library without
      // 'header: true' in its definition is still loaded in the header when a
      // header library depends on it. That page context is not available here,
      // so the resolved scope cannot be trusted. Use all resolved assets and
      // set the scope from the URL, restoring the render-time sort order so
      // the generated hash matches.

Given the asset will have all assets from all libraries, I think rather than forcing scope to be what's in the URL, we should ignore scope entirely and grab all the assets, which will mean we don't need to set scope in the URL at all. Should result in the same resulting file in the end and ought to be easier to follow.

When using the include/exclude pattern we'll still need to use scope in the URL, but once we have before/after fully implemented and weights deprecated/removed we should be able to remove includes/exclude entirely.

catch’s picture

Title: JS gets broken when enabling default_admin on clean install » JS aggregation returns 400 for libraries loaded in the header only as dependencies
Component: Admin theme » asset library system
Priority: Normal » Major

crosspost...

catch’s picture

Status: Active » Needs work
mherchel’s picture

I'm going to leave this for people who understand the code a bit better. I don't want to be a meat puppet for Claude, unless absolutely needed

catch’s picture

Pushed a commit for #26.

I didn't review the test coverage properly yet, however the new code passes the new test coverage. I did have to make one small change - the test looks for scope to determine header libraries but it won't always be there now. This may cause different test failures, but hopefully only test expectations rather than real ones..

catch’s picture

Had a quick look at the tests. It mostly looked OK except for the filler content in the test file asset which claimed it needed to be there because web browsers skip compression under a certain length, removed it and the tests pass without it so I think that is probably Claude making things over complicated for no reason.

With the scope removed we can't absolutely be sure that the header js file being looked for is actually in the header (e.g. it could actually be in the footer instead), but we're really testing whether the header file produces a 400 response or not so I think that's probably OK? If not we'd have to parse the HTML to get URLs only before the body tag or similar. But we have more general test coverage that header files end up in the header I think.

I do get test failures running that test locally due to lack of brotli support in ddev's PHP but that's pre-existing and not affected by the MR. There's an open issue for it here but it's blocked on upstream https://github.com/ddev/ddev/issues/8549

catch’s picture

Priority: Major » Critical
Status: Needs work » Needs review

This completely breaks js in default_admin so moving to critical.

mherchel’s picture

Status: Needs review » Reviewed & tested by the community

Tested in default_admin, and with the MR, the JS works again in default-admin.

Thank you!

godotislate’s picture

Status: Reviewed & tested by the community » Needs review

2 comments on the MR.

catch’s picture

Status: Needs review » Needs work

Applied both of the suggestions because they looked reasonable, but now the tests are failing.

godotislate’s picture

Status: Needs work » Needs review

Found the issue. In core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php, this change

unset($query['include'], $query['exclude'], $query['delta'], $query['scope']);

was removing scope from the JS aggregrate URL query string, so changing it back to

unset($query['include'], $query['exclude'], $query['delta']);

fixed it.

I've confirmed in browser with standard install + default_admin that aggregated JS has no console errors.

Tests are green again, and test only fails as expected: https://git.drupalcode.org/project/drupal/-/jobs/11644653

catch’s picture

It should be OK to remove the scope from the query string when libraries is set, because it's ignored now in that case.

godotislate’s picture

Oh, OK, so maybe the issue is with the test.

    $header_dependency_aggregates = array_filter($script_urls, function (string $url): bool {
      $query = UrlHelper::parse($this->getAbsoluteUrl($url))['query'];
      if (($query['scope'] ?? NULL) !== 'header' || !isset($query['libraries'])) {
        return FALSE;
      }
      return str_contains(UrlHelper::uncompressQueryParameter($query['libraries']), 'core/drupal');
    });
    $this->assertNotEmpty($header_dependency_aggregates);

When I debugged, before adding the scope back to the query params, none of $script_urls contained a scope, so $header_dependency_aggregates ends up being empty. Do we need to do something like query the DOM to see if there are script tags in the <head> for the expected aggregated JS files?

catch’s picture

See #31 I made the check a bit looser since we're really checking whether the header is a 400. Other tests check whether files end up in the header. If we parsed the script tags it would be better but not sure it's necessary to demonstrate the bug is fixed. Test only run should definitely fail.

godotislate’s picture

OK, removed scope from query string again. Adjusted the test just to make sure there's one script URL that has core/drupal. Test only still fails as expected with 400: https://git.drupalcode.org/project/drupal/-/jobs/11647160

mherchel’s picture

Status: Needs review » Reviewed & tested by the community

Verified no console errors with the new changes. Tests are passing!

  • godotislate committed e29fc199 on 11.x
    fix: #3614911 JS aggregation returns 400 for libraries loaded in the...

  • godotislate committed 668d8beb on main
    fix: #3614911 JS aggregation returns 400 for libraries loaded in the...
godotislate’s picture

Version: main » 11.x-dev
Status: Reviewed & tested by the community » Fixed

I only made a pretty minor test change, so I think I can commit this.

Committed and pushed 668d8be to main and e29fc19 to 11.x. Thanks!

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.

mherchel’s picture

Any chance we can get this into 11.4.x?

We can't wait for 11.5 if we want module maintainers to test their UIs in Default Admin before D12. And this bug breaks the theme .

catch’s picture

@mherchel the issue that introduced this is only in 11.x, not 11.4: #3565258: Support library-specific aggregates