⚓ T357477 InvalidArgumentException: Script must be a string or array
Page MenuHomePhabricator

InvalidArgumentException: Script must be a string or array
Closed, ResolvedPublicPRODUCTION ERROR

Description

Error
normalized_message
[{reqId}] {exception_url}   InvalidArgumentException: Script must be a string or array
exception.trace
from /srv/mediawiki/php-1.42.0-wmf.17/includes/ResourceLoader/ResourceLoader.php(1425)
#0 /srv/mediawiki/php-1.42.0-wmf.17/includes/ResourceLoader/ResourceLoader.php(1329): MediaWiki\ResourceLoader\ResourceLoader->addImplementScript(Wikimedia\Minify\IdentityMinifierState, string, string, boolean, array, NULL, array, NULL)
#1 /srv/mediawiki/php-1.42.0-wmf.17/includes/ResourceLoader/ResourceLoader.php(1194): MediaWiki\ResourceLoader\ResourceLoader->addOneModuleResponse(MediaWiki\ResourceLoader\Context, Wikimedia\Minify\IdentityMinifierState, string, MediaWiki\ResourceLoader\UserModule, array)
#2 /srv/mediawiki/php-1.42.0-wmf.17/includes/ResourceLoader/ResourceLoader.php(1118): MediaWiki\ResourceLoader\ResourceLoader->getOneModuleResponse(MediaWiki\ResourceLoader\Context, string, MediaWiki\ResourceLoader\UserModule)
#3 /srv/mediawiki/php-1.42.0-wmf.17/includes/ResourceLoader/ResourceLoader.php(830): MediaWiki\ResourceLoader\ResourceLoader->makeModuleResponse(MediaWiki\ResourceLoader\Context, array, array)
#4 /srv/mediawiki/php-1.42.0-wmf.17/includes/ResourceLoader/ResourceEntryPoint.php(52): MediaWiki\ResourceLoader\ResourceLoader->respond(MediaWiki\ResourceLoader\Context)
#5 /srv/mediawiki/php-1.42.0-wmf.17/includes/MediaWikiEntryPoint.php(201): MediaWiki\ResourceLoader\ResourceEntryPoint->execute()
#6 /srv/mediawiki/php-1.42.0-wmf.17/load.php(45): MediaWiki\MediaWikiEntryPoint->run()
#7 /srv/mediawiki/w/load.php(3): require(string)
#8 {main}
Impact

The requested module is not returned. Whether this breaks an extension or core feature is TBD.

Notes

One microsecond before the above exception is logged, ResourceLoader reports a diagnostic message to channel=ResourceLoader with a more detailed version of the same stack trace:

InvalidArgumentException: Script must be a string or array in /srv/mediawiki/php-1.42.0-wmf.17/includes/ResourceLoader/ResourceLoader.php:1425
Stack trace:
#0 /srv/mediawiki/php-1.42.0-wmf.17/includes/ResourceLoader/ResourceLoader.php(1329): MediaWiki\ResourceLoader\ResourceLoader->addImplementScript(Object(Wikimedia\Minify\IdentityMinifierState), 'user', 'dzt6e', false, Array, NULL, Array, NULL)

The stack trace reveals which value is pased, namely false to addImplementScript() where for $scripts we expect the value of string or array.

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

It appears this happens consistently via https://en.wikipedia.org/w/load.php?lang=en&modules=user&skin=vector&user=MCGAMER+YOUTUBE, and originates from
https://en.wikipedia.org/w/index.php?title=User:MCGAMER_YOUTUBE/common.js&oldid=1016679869.

It doesn't happen for other user names.

The page in question constains some obviously-invalid content (the author mistakenly placed CSS code in their JS page). However, we have validation for this, and there is no reason why that should cause the internal RL code to pass an invalid argument type between two functions.

The call order is roughly as follows:

  • addOneModuleResponse() passes $scripts to addImplementScript(), where $script is bool(false) instead of array or string.
  • addOneModuleResponse() calls $module->getModuleContent()
  • Module::buildContent()
  • Module::getScript()
  • WikiModule::getScript()
  • WikiModule::getContent() - gets the string from the Revision store
  • Module::validateScriptFile() - uses Peast to check for syntax errors.
  • some time later: JavaScriptMinifier

I can reproduce this locally as well, and have reduced the problem to the following input on my User:Admin/common.js page:

/* Comment */
@import url('https://example');
html { font-size: 1em; }

Where http://localhost:4000/load.php?lang=en&modules=user&skin=vector&user=Admin then fails with Fatal exception of type "InvalidArgumentException" */.

The issue appears very specific to a combinations of these three tokens: Comment, @import and font-size: 1rem. For example, changing the last line from font-size: 1em to font-size: normal means we serve a string (and Peast gracefully renders a syntax error message in the form of valid JS as replacement code). Or, omitting the comment line, makes it work as well. Or, omitting the @import line also makes it work fine.

So we've found a bug in Peast, where it doesn't find syntax errors in certain cases. However, that still doesn't explain how this (supposedly valid) JS string turns into bool(false).

I have meanwhile reported it upstream at https://github.com/mck89/peast/issues/67, but as stated, this is not the root cause. *Something* else, after validateScriptFile() is done, is at some point turning the string into bolean false.

Change 1003436 had a related patch set uploaded (by Krinkle; author: Krinkle):

[mediawiki/libs/Minify@master] JavaScriptMinifier: Change minify() to no longer return false

https://gerrit.wikimedia.org/r/1003436

Krinkle triaged this task as Medium priority.Feb 15 2024, 5:00 PM
Krinkle added a subscriber: Hokwelum.

@Hokwelum Can you prepare a commit to mediawiki/vendor and mediawiki/core that updates Peast?

Change 1004045 had a related patch set uploaded (by Hokwelum; author: Hokwelum):

[mediawiki/core@master] Updated mck89/peast from 1.16.0 to 1.16.1

https://gerrit.wikimedia.org/r/1004045

Change 1004044 had a related patch set uploaded (by Hokwelum; author: Hokwelum):

[mediawiki/vendor@master] Update mck89/peast from v1.16.0 to v1.16.1

https://gerrit.wikimedia.org/r/1004044

Change 1004044 merged by jenkins-bot:

[mediawiki/vendor@master] Update mck89/peast from v1.16.0 to v1.16.1

https://gerrit.wikimedia.org/r/1004044

Change 1004045 merged by jenkins-bot:

[mediawiki/core@master] Updated mck89/peast from 1.16.0 to 1.16.1

https://gerrit.wikimedia.org/r/1004045

Change 1003436 merged by jenkins-bot:

[mediawiki/libs/Minify@master] JavaScriptMinifier: Change minify() to no longer return false

https://gerrit.wikimedia.org/r/1003436