Page MenuHomePhabricator

Singleton was called with no singleton theme set
Open, Needs TriagePublicBUG REPORT

Description

Hello, since I upgraded from MediaWiki 1.40.0 to 1.41.0, my Nginx log file is flooded with this error:

2024/03/15 02:58:42 [error] 12345#0: *1234567 FastCGI sent in stderr: "PHP message: PHP Fatal error:  OOUI\Exception: OOUI\Theme::singleton was called with no singleton theme set. in /path/to/my/wiki/vendor/oojs/oojs-ui/php/Theme.php:31
Stack trace:
#0 /path/to/my/wiki/vendor/oojs/oojs-ui/php/Element.php(259): OOUI\Theme::singleton()
#1 /path/to/my/wiki/vendor/oojs/oojs-ui/php/Tag.php(507): OOUI\Element->toString()
#2 /path/to/my/wiki/extensions/VisualEditor/includes/Hooks.php(244): OOUI\Tag->__toString()
#3 /path/to/my/wiki/includes/HookContainer/HookContainer.php(161): MediaWiki\Extension\VisualEditor\Hooks->onTextSlotDiffRendererTablePrefix()
#4 /path/to/my/wiki/includes/HookContainer/HookRunner.php(1334): MediaWiki\HookContainer\HookContainer->run()
#5 /path/to/my/wiki/includes/diff/TextSlotDiffRenderer.php(273): MediaWiki\HookContainer\HookRunner->onTextSlotDiffRendererTablePrefix()
#6 /path/to/my/wiki/includes/diff/DifferenceEngine.php(942): TextSlotDiffRenderer->getTablePrefix()
#7 /path/to/my/wiki/includes/diff/DifferenceEngine.php(928): DifferenceEngine->showTablePrefixes()
#8 /path/to/my/wiki/includes/page/Article.php(979): DifferenceEngine->showDiffPage()
#9 /path/to/my/wiki/includes/page/Article.php(490): Article->showDiffPage()
#10 /path/to/my/wiki/includes/actions/ViewAction.php(78): Article->view()
#11 /path/to/my/wiki/includes/MediaWiki.php(583): ViewAction->show()
#12 /path/to/my/wiki/includes/MediaWiki.php(363): MediaWiki->performAction()
#13 /path/to/my/wiki/includes/MediaWiki.php(960): MediaWiki->performRequest()
#14 /path/to/my/wiki/includes/MediaWiki.php(613): MediaWiki->main()
#15 /path/to/my/wiki/index.php(50): MediaWiki->run()
#16 /path/to/my/wiki/index.php(46): wfIndexMain()
#17 {main}" while reading response header from upstream, client: 123.45.67.89, server: my.wiki.com, request: "GET /w/index.php?diff=193481&oldid=prev&title=Article_Name HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: " my.wiki.com"

When I disable the VisualEditor extension, the error is gone.

Steps to replicate the issue:

  • Go to the latest revision of an article (NSFW).
  • Add "&diff=prev" to that URL (NSFW).

What happens?

The browser shows a blank page or HTTP error 500 and the error mentioned above is added to the log file.

What should have happened instead?

A page like this should be shown with the text: "(No difference)".

Software version:

OpenBSD 7.4, Nginx 1.24.0, PHP 8.1.25 (fpm-fcgi), MariaDB 10.9.6, Memcached 1.6.15, and MediaWiki 1.41.0, with REL1_41 extensions.

Event Timeline

We found similar messages in our logs, but &diff=prev works for us and seems to not be the reason for the problem.
(Example link similar to OP's one works fine: Click here (SFW))

We're not sure where it comes from.

[Tue Mar 26 14:53:53.221941 2024] [proxy_fcgi:error] [pid 3591409] [client 172.70.42.174:0] AH01071: Got error 'PHP message: PHP Fatal error: OOUI\\Exception: OOUI\\Theme::singleton was called with no singleton theme set. in /var/www/vhosts/domain.com/httpdocs/vendor/oojs/oojs-ui/php/Theme.php:31
Stack trace:
#0 /var/www/vhosts/domain.com/httpdocs/vendor/oojs/oojs-ui/php/Element.php(259): OOUI\\Theme::singleton()
#1 /var/www/vhosts/domain.com/httpdocs/vendor/oojs/oojs-ui/php/Tag.php(507): OOUI\\Element->toString()\
#2 /var/www/vhosts/domain.com/httpdocs/extensions/VisualEditor/includes/Hooks.php(244): OOUI\\Tag->__toString()\
#3 /var/www/vhosts/domain.com/httpdocs/includes/HookContainer/HookContainer.php(161): MediaWiki\\Extension\\VisualEditor\\Hooks->onTextSlotDiffRendererTablePrefix()\
#4 /var/www/vhosts/domain.com/httpdocs/includes/HookContainer/HookRunner.php(1332): MediaWiki\\HookContainer\\HookContainer->run()
#5 /var/www/vhosts/domain.com/httpdocs/includes/diff/TextSlotDiffRenderer.php(273): MediaWiki\\HookContainer\\HookRunner->onTextSlotDiffRendererTablePrefix()\n#6 /var/www/vhosts/domain.com/htt...'

Ubuntu 22.04 LTS, PHP 8.3.4, MediaWiki 1.41.0

I just upgraded to MediaWiki version 1.41.1 but it didn't fix the error.

I also observe this exception on MW 1.41.1 with VE REL1_41 on PHP 7.4. I wonder how crawlers find these links, they are not displayed by MediaWiki in the history page, so either they appear somewhere I’m not aware, either they are constructed by MediaWiki-optimised crawlers to crawl the histories.

We found similar messages in our logs, but &diff=prev works for us and seems to not be the reason for the problem.
(Example link similar to OP's one works fine: Click here (SFW))

You have also the issue: normal diffs works fine, but it’s the diff between the first revision in the history and the previous one (which don’t exist, but it should display a nice error); on your example it is this link.

I completed the stacktrace in the description (log_errors_max_len has to be set to a larger value than 1024, like 2048).

Below is a normal stacktrace when viewing a diff:

#0  MediaWiki\Output\OutputPage::setupOOUI() called at [/path/to/my/wiki/includes/Output/OutputPage.php:4717]
#1  MediaWiki\Output\OutputPage->enableOOUI() called at [/path/to/my/wiki/extensions/VisualEditor/includes/Hooks.php:202]
#2  MediaWiki\Extension\VisualEditor\Hooks->onDifferenceEngineViewHeader() called at [/path/to/my/wiki/includes/HookContainer/HookContainer.php:161]
#3  MediaWiki\HookContainer\HookContainer->run() called at [/path/to/my/wiki/includes/HookContainer/HookRunner.php:1442]
#4  MediaWiki\HookContainer\HookRunner->onDifferenceEngineViewHeader() called at [/path/to/my/wiki/includes/diff/DifferenceEngine.php:724]
#5  DifferenceEngine->showDiffPage() called at [/path/to/my/wiki/includes/page/Article.php:979]
#6  Article->showDiffPage() called at [/path/to/my/wiki/includes/page/Article.php:490]
#7  Article->view() called at [/path/to/my/wiki/includes/actions/ViewAction.php:78]
#8  ViewAction->show() called at [/path/to/my/wiki/includes/MediaWiki.php:583]
#9  MediaWiki->performAction() called at [/path/to/my/wiki/includes/MediaWiki.php:363]
#10 MediaWiki->performRequest() called at [/path/to/my/wiki/includes/MediaWiki.php:960]
#11 MediaWiki->main() called at [/path/to/my/wiki/includes/MediaWiki.php:613]
#12 MediaWiki->run() called at [/path/to/my/wiki/index.php:50]
#13 wfIndexMain() called at [/path/to/my/wiki/index.php:46]

The difference is in DifferenceEngine.php: when there is an old revision, the hook DifferenceEngineViewHeader is called by VisualEditor, which enables OOUI ($output->enableOOUI()), else it is not called and OOUI triggers an exception.


Fix: It can be fixed in the VisualEditor by copying the code from MediaWiki\Extension\VisualEditor\Hooks::onDifferenceEngineViewHeader (file extensions/VisualEditor/includes/Hooks.php) into MediaWiki\Extension\VisualEditor::onTextSlotDiffRendererTablePrefix before the use of ButtonWidget:

@@ -227,6 +227,16 @@ class Hooks implements
 			return;
 		}
 
+		$output->addModuleStyles( [
+			'ext.visualEditor.diffPage.init.styles',
+			'oojs-ui.styles.icons-accessibility',
+			'oojs-ui.styles.icons-editing-advanced'
+		] );
+		// T344596: Must load this module unconditionally. The TextSlotDiffRendererTablePrefix hook
+		// below doesn't run when the diff is e.g. a log entry with no change to the content.
+		$output->addModules( 'ext.visualEditor.diffPage.init' );
+		$output->enableOOUI();
+
 		$parts['50_ve-init-mw-diffPage-diffMode'] = '<div class="ve-init-mw-diffPage-diffMode">' .
 			// Will be replaced by a ButtonSelectWidget in JS
 			new ButtonGroupWidget( [

But probably the call to the hook DifferenceEngineViewHeader is not needed in this case.

An alternative easy fix is to in includes/diff/DifferenceEngine.php:

@@ -923,5 +923,3 @@ class DifferenceEngine extends ContextSource {
 			// Check if inline switcher will be needed
-			if ( $this->getTextDiffer()->hasFormat( 'inline' ) ) {
-				$out->enableOOUI();
-			}
+			$out->enableOOUI();

Fix: It can be fixed in the VisualEditor by copying the code from MediaWiki\Extension\VisualEditor\Hooks::onDifferenceEngineViewHeader (file extensions/VisualEditor/includes/Hooks.php) into MediaWiki\Extension\VisualEditor::onTextSlotDiffRendererTablePrefix before the use of ButtonWidget:

It works perfectly now! Thank you so much for your help! Cheers and all the best!

Ah, you were right! Also applied that fix and the problem is resolved for now.

Fix: It can be fixed in the VisualEditor by copying the code from MediaWiki\Extension\VisualEditor\Hooks::onDifferenceEngineViewHeader (file extensions/VisualEditor/includes/Hooks.php) into MediaWiki\Extension\VisualEditor::onTextSlotDiffRendererTablePrefix before the use of ButtonWidget:

@@ -227,6 +227,16 @@ class Hooks implements
 			return;
 		}
 
+		$output->addModuleStyles( [
+			'ext.visualEditor.diffPage.init.styles',
+			'oojs-ui.styles.icons-accessibility',
+			'oojs-ui.styles.icons-editing-advanced'
+		] );
+		// T344596: Must load this module unconditionally. The TextSlotDiffRendererTablePrefix hook
+		// below doesn't run when the diff is e.g. a log entry with no change to the content.
+		$output->addModules( 'ext.visualEditor.diffPage.init' );
+		$output->enableOOUI();
+
 		$parts['50_ve-init-mw-diffPage-diffMode'] = '<div class="ve-init-mw-diffPage-diffMode">' .
 			// Will be replaced by a ButtonSelectWidget in JS
 			new ButtonGroupWidget( [

This seems to be the change done in T361775. I tried backporting the change to REL1_41, but it didn't fix it. As mentioned, I moved the adding of the styles above the button and then it did work.