Page MenuHomePhabricator

TypeError: MediaWiki\Parser\Parser::expandMagicVariable(): Return value must be of type string, null returned
Closed, ResolvedPublicPRODUCTION ERROR

Description

Error
  • service.version: 1.46.0-wmf.19
  • timestamp: 2026-03-12T14:22:35.521Z
  • labels.phpversion: 8.3.30
  • trace.id: c282857d-34e7-4ea6-a525-4fac5e67295d
  • Find trace.id in Logstash
labels.normalized_message
[{reqId}] {exception_url}   TypeError: MediaWiki\Parser\Parser::expandMagicVariable(): Return value must be of type string, null returned
FrameLocationCall
from/srv/mediawiki/php-1.46.0-wmf.19/includes/Parser/Parser.php(2774)
#0/srv/mediawiki/php-1.46.0-wmf.19/includes/Parser/Parser.php(3008)MediaWiki\Parser\Parser->expandMagicVariable(string, MediaWiki\Parser\PPFrame_Hash)
#1/srv/mediawiki/php-1.46.0-wmf.19/includes/Parser/PPFrame_Hash.php(267)MediaWiki\Parser\Parser->braceSubstitution(array, MediaWiki\Parser\PPFrame_Hash)
#2/srv/mediawiki/php-1.46.0-wmf.19/includes/Parser/Parser.php(2954)MediaWiki\Parser\PPFrame_Hash->expand(MediaWiki\Parser\PPNode_Hash_Tree)
#3/srv/mediawiki/php-1.46.0-wmf.19/includes/Parser/PPFrame_Hash.php(267)MediaWiki\Parser\Parser->braceSubstitution(array, MediaWiki\Parser\PPFrame_Hash)
#4/srv/mediawiki/php-1.46.0-wmf.19/includes/Parser/Parser.php(2866)MediaWiki\Parser\PPFrame_Hash->expand(MediaWiki\Parser\PPNode_Hash_Tree, int)
#5/srv/mediawiki/php-1.46.0-wmf.19/includes/Parser/Parser.php(1498)MediaWiki\Parser\Parser->replaceVariables(string)
#6/srv/mediawiki/php-1.46.0-wmf.19/includes/Parser/Parser.php(623)MediaWiki\Parser\Parser->internalParse(string)
#7/srv/mediawiki/php-1.46.0-wmf.19/includes/Content/WikitextContentHandler.php(375)MediaWiki\Parser\Parser->parse(string, MediaWiki\Title\Title, MediaWiki\Parser\ParserOptions, bool, bool, int)
#8/srv/mediawiki/php-1.46.0-wmf.19/includes/Content/ContentHandler.php(1574)MediaWiki\Content\WikitextContentHandler->fillParserOutput(MediaWiki\Content\WikitextContent, MediaWiki\Content\Renderer\ContentParseParams, MediaWiki\Parser\ParserOutput)
#9/srv/mediawiki/php-1.46.0-wmf.19/includes/Content/Renderer/ContentRenderer.php(67)MediaWiki\Content\ContentHandler->getParserOutput(MediaWiki\Content\WikitextContent, MediaWiki\Content\Renderer\ContentParseParams)
#10/srv/mediawiki/php-1.46.0-wmf.19/includes/Revision/RenderedRevision.php(246)MediaWiki\Content\Renderer\ContentRenderer->getParserOutput(MediaWiki\Content\WikitextContent, MediaWiki\Page\PageIdentityValue, MediaWiki\Revision\RevisionStoreRecord, MediaWiki\Parser\ParserOptions, array)
#11/srv/mediawiki/php-1.46.0-wmf.19/includes/Revision/RenderedRevision.php(219)MediaWiki\Revision\RenderedRevision->getSlotParserOutputUncached(MediaWiki\Content\WikitextContent, array)
#12/srv/mediawiki/php-1.46.0-wmf.19/includes/Revision/RevisionRenderer.php(225)MediaWiki\Revision\RenderedRevision->getSlotParserOutput(string, array)
#13/srv/mediawiki/php-1.46.0-wmf.19/includes/Revision/RevisionRenderer.php(158)MediaWiki\Revision\RevisionRenderer->combineSlotOutput(MediaWiki\Revision\RenderedRevision, MediaWiki\Parser\ParserOptions, array)
#14/srv/mediawiki/php-1.46.0-wmf.19/includes/Revision/RenderedRevision.php(182)MediaWiki\Revision\RevisionRenderer->MediaWiki\Revision\{closure}(MediaWiki\Revision\RenderedRevision, array)
#15/srv/mediawiki/php-1.46.0-wmf.19/includes/Page/ParserOutputAccess.php(593)MediaWiki\Revision\RenderedRevision->getRevisionParserOutput()
#16/srv/mediawiki/php-1.46.0-wmf.19/includes/Page/ParserOutputAccess.php(508)MediaWiki\Page\ParserOutputAccess->renderRevision(MediaWiki\Page\WikiPage, MediaWiki\Parser\ParserOptions, MediaWiki\Revision\RevisionStoreRecord, array, null)
#17/srv/mediawiki/php-1.46.0-wmf.19/includes/Diff/DifferenceEngine.php(1265)MediaWiki\Page\ParserOutputAccess->getParserOutput(MediaWiki\Page\WikiPage, MediaWiki\Parser\ParserOptions, MediaWiki\Revision\RevisionStoreRecord, array)
#18/srv/mediawiki/php-1.46.0-wmf.19/includes/Diff/DifferenceEngine.php(1055)MediaWiki\Diff\DifferenceEngine->renderNewRevision()
#19/srv/mediawiki/php-1.46.0-wmf.19/includes/Page/Article.php(1143)MediaWiki\Diff\DifferenceEngine->showDiffPage(bool)
#20/srv/mediawiki/php-1.46.0-wmf.19/includes/Page/Article.php(483)MediaWiki\Page\Article->showDiffPage()
#21/srv/mediawiki/php-1.46.0-wmf.19/includes/Actions/ViewAction.php(71)MediaWiki\Page\Article->view()
#22/srv/mediawiki/php-1.46.0-wmf.19/includes/Actions/ActionEntryPoint.php(739)MediaWiki\Actions\ViewAction->show()
#23/srv/mediawiki/php-1.46.0-wmf.19/includes/Actions/ActionEntryPoint.php(510)MediaWiki\Actions\ActionEntryPoint->performAction(MediaWiki\Page\Article, MediaWiki\Title\Title)
#24/srv/mediawiki/php-1.46.0-wmf.19/includes/Actions/ActionEntryPoint.php(144)MediaWiki\Actions\ActionEntryPoint->performRequest()
#25/srv/mediawiki/php-1.46.0-wmf.19/includes/MediaWikiEntryPoint.php(180)MediaWiki\Actions\ActionEntryPoint->execute()
#26/srv/mediawiki/php-1.46.0-wmf.19/index.php(44)MediaWiki\MediaWikiEntryPoint->run()
#27/srv/mediawiki/w/index.php(3)require(string)
#28{main}
Impact
Notes

13 of these in T413810.

Related to T417284: TypeError: MediaWiki\Parser\CoreMagicVariables::expand(): Return value must be of type ?string, array returned?

Event Timeline

Change #1260641 had a related patch set uploaded (by Thiemo Kreuz (WMDE); author: Thiemo Kreuz (WMDE)):

[mediawiki/extensions/WikiLambda@master] Don't register magic words we don't plan to handle

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

Change #1260647 had a related patch set uploaded (by Thiemo Kreuz (WMDE); author: Thiemo Kreuz (WMDE)):

[mediawiki/core@master] Add safe-guard and docs to ParserGetVariableValueSwitch hook

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

thiemowmde subscribed.

According to the stack trace this is the result of an extension not using the ParserGetVariableValueSwitch hook correctly. In an ideal world there should always be exactly one extension thats responsible for a magic word and sets the out-parameter &$ret to a string.

It looks like we have a situation here where an extension registered a magic word, then the hook asked all registered hook handlers to provide a non-null return value, but none of the extensions did that.

The stack trace above is from an old revision from the article https://vi.wiktionary.org/wiki/Phụ_lục:Ngôn_ngữ. In my test all old revisions of this article currently fail, except for the very last where {{NUMBEROFLANGUAGES}} was replaced with {{NUMBEROFLANGUAGES1}}. That's a WikiLambda magic word.

Another problem I see is that the core Parser code that calls the hook handlers can only assume that it will get a string from some of the registered hook handlers. But each individual hook handler is actually allowed to return null. What if all return null? There is nothing we can do to enforce this.

None of our magic words should be registered on viwiktionary. They don't show up on https://vi.wiktionary.org/wiki/%C4%90%E1%BA%B7c_bi%E1%BB%87t:Phi%C3%AAn_b%E1%BA%A3n but are getting called anyway? We can escape in onGetMagicVariableIDs but we already do that on onParserGetVariableValueSwitch.

Change #1260673 had a related patch set uploaded (by Jforrester; author: Jforrester):

[mediawiki/extensions/WikiLambda@master] PageRenderingHandler::onGetMagicVariableIDs: Only register in repo mode

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

Change #1260673 abandoned by Jforrester:

[mediawiki/extensions/WikiLambda@master] PageRenderingHandler::onGetMagicVariableIDs: Only register in repo mode

Reason:

If981955a1021bf8d3d6867d2bee794269e03f046 was pushed first but people who are irritated that tasks get worked on decided to hide things.

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

Change #1260641 merged by jenkins-bot:

[mediawiki/extensions/WikiLambda@master] Don't register magic words we don't plan to handle

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

Change #1260754 had a related patch set uploaded (by C. Scott Ananian; author: C. Scott Ananian):

[mediawiki/core@master] Report magic words which expand to null

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

Change #1260754 merged by jenkins-bot:

[mediawiki/core@master] Report magic words which expand to null

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

Change #1260647 abandoned by Thiemo Kreuz (WMDE):

[mediawiki/core@master] Add safe-guard and docs to ParserGetVariableValueSwitch hook

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