Page MenuHomePhabricator

BlockManager->trackBlockWithCookie triggers "Recursion detected in RequestContext::getLanguage" warning
Closed, ResolvedPublic

Description

Error

Request URL: /w/api.php?format=json&formatversion=2&errorformat=plaintext&action=query&meta=siteinfo
Request ID: XRU58gpAIDgAAAlPkeUAAABB

message
Warning: Recursion detected in RequestContext::getLanguage
trace
#0 /srv/mediawiki/php-1.34.0-wmf.11/includes/context/RequestContext.php(322): MWExceptionHandler::handleError(integer, string, string, integer, array, array)
#1 /srv/mediawiki/php-1.34.0-wmf.11/includes/language/Message.php(393): RequestContext->getLanguage()
#2 /srv/mediawiki/php-1.34.0-wmf.11/includes/language/Message.php(1308): Message->getLanguage()
#3 /srv/mediawiki/php-1.34.0-wmf.11/includes/language/Message.php(863): Message->fetchMessage()
#4 /srv/mediawiki/php-1.34.0-wmf.11/includes/language/Message.php(967): Message->toString(string)
#5 /srv/mediawiki/php-1.34.0-wmf.11/includes/block/BlockManager.php(215): Message->plain()
#6 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(1817): MediaWiki\Block\BlockManager->getUserBlock(User, boolean)
#7 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(2143): User->getBlockedStatus(boolean)
#8 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(1356): User->getBlock()
#9 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(451): User->loadFromSession()
#10 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(5283): User->load()
#11 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(3024): User->loadOptions()
#12 /srv/mediawiki/php-1.34.0-wmf.11/includes/context/RequestContext.php(337): User->getOption(string)
#13 /srv/mediawiki/php-1.34.0-wmf.11/includes/context/DerivativeContext.php(232): RequestContext->getLanguage()
#14 /srv/mediawiki/php-1.34.0-wmf.11/includes/context/ContextSource.php(129): DerivativeContext->getLanguage()
#15 /srv/mediawiki/php-1.34.0-wmf.11/includes/api/ApiMain.php(265): ContextSource->getLanguage()
#16 /srv/mediawiki/php-1.34.0-wmf.11/api.php(68): ApiMain->__construct(RequestContext, boolean)
#17 /srv/mediawiki/w/api.php(3): include(string)
#18 {main}

Impact

The user's language preference for the wiki interface will be ignored for some requests; falling back to the site's default language.

This is due to the use of functions that vary by user-language, being called while the user information itself is being initialised, which is invalid.

Notes

Regression first seen in the 1.35-wmf.11 deployment today.

From Logstash:

  • Affects multiple wikis, including en.wikipedia and ru.wikipedia.
  • Affects both PHP7 and HHVM.
  • Errors appear to come distributed from different web servers.

Event Timeline

Krinkle created this task.Jun 27 2019, 9:51 PM
Restricted Application added subscribers: MGChecker, Aklapper. · View Herald TranscriptJun 27 2019, 9:51 PM

Another sample of what appears to be the same issue, but with a different stack trace:

reqId: e3e7f4e0-9925-11e9-8be4-f1e7ea9077c5

#0 /srv/mediawiki/php-1.34.0-wmf.11/includes/context/RequestContext.php(322): MWExceptionHandler::handleError(integer, string, string, integer, array, array)
#1 /srv/mediawiki/php-1.34.0-wmf.11/includes/language/Message.php(393): RequestContext->getLanguage()
#2 /srv/mediawiki/php-1.34.0-wmf.11/includes/language/Message.php(1308): Message->getLanguage()
#3 /srv/mediawiki/php-1.34.0-wmf.11/includes/language/Message.php(863): Message->fetchMessage()
#4 /srv/mediawiki/php-1.34.0-wmf.11/includes/language/Message.php(967): Message->toString(string)
#5 /srv/mediawiki/php-1.34.0-wmf.11/includes/block/BlockManager.php(215): Message->plain()
#6 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(1817): MediaWiki\Block\BlockManager->getUserBlock(User, boolean)
#7 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(2143): User->getBlockedStatus(boolean)
#8 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(1356): User->getBlock()
#9 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(451): User->loadFromSession()
#10 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(5283): User->load()
#11 /srv/mediawiki/php-1.34.0-wmf.11/includes/user/User.php(3024): User->loadOptions()
#12 /srv/mediawiki/php-1.34.0-wmf.11/includes/context/RequestContext.php(337): User->getOption(string)
#13 /srv/mediawiki/php-1.34.0-wmf.11/includes/context/DerivativeContext.php(232): RequestContext->getLanguage()
#14 /srv/mediawiki/php-1.34.0-wmf.11/includes/language/Message.php(725): DerivativeContext->getLanguage()
#15 /srv/mediawiki/php-1.34.0-wmf.11/includes/context/DerivativeContext.php(266): Message->setContext(DerivativeContext)
#16 /srv/mediawiki/php-1.34.0-wmf.11/includes/context/ContextSource.php(171): DerivativeContext->msg(string, string)
#17 /srv/mediawiki/php-1.34.0-wmf.11/extensions/ReadingLists/src/Api/ApiQueryReadingListEntries.php(141): ContextSource->msg(string, string)
#18 /srv/mediawiki/php-1.34.0-wmf.11/includes/api/ApiBase.php(2339): MediaWiki\Extensions\ReadingLists\Api\ApiQueryReadingListEntries->getAllowedParams(integer)
#19 /srv/mediawiki/php-1.34.0-wmf.11/includes/api/ApiBase.php(773): ApiBase->getFinalParams()
#20 /srv/mediawiki/php-1.34.0-wmf.11/includes/api/ApiQuery.php(247): ApiBase->extractRequestParams()
#21 /srv/mediawiki/php-1.34.0-wmf.11/includes/api/ApiMain.php(1583): ApiQuery->execute()
#22 /srv/mediawiki/php-1.34.0-wmf.11/includes/api/ApiMain.php(531): ApiMain->executeAction()
#23 /srv/mediawiki/php-1.34.0-wmf.11/includes/api/ApiMain.php(502): ApiMain->executeActionWithErrorHandling()
#24 /srv/mediawiki/php-1.34.0-wmf.11/api.php(87): ApiMain->execute()
#25 /srv/mediawiki/w/api.php(3): include(string)
Niharika triaged this task as Medium priority.Jun 27 2019, 11:37 PM
Niharika moved this task from Untriaged to The Letter Song on the Anti-Harassment board.

This is similar to T180050. The problem is here:

https://gerrit.wikimedia.org/g/mediawiki/core/+/647e0709aecf59b77af8114d2c79dc5eeef514f9/includes/block/BlockManager.php#215

...which is called when a composite block is created. The same problem occurs if any type of system block is created, which is why the issue existed previously. It seems that composite blocks are a lot more common than system blocks, which is why the problem has become worse.

We're going to look at solving these circular dependencies while we improve block errors in the course of fixing T212326, but in the meantime there's a fix here: https://gerrit.wikimedia.org/r/#/c/mediawiki/core/+/519177/

For future reference and to be verbose, the recursion comes from the use of wfMessage() within BlockManager. More specifically, the use of Message objects without an explicitly specified language to use, and to then actually format the message into its final form.

A few ideas:

  • As a very short-term workaround, we can defer the whole use of BlockManager, as the above patch does for the cookie enforcement feature. There may be other uses of BlockManager in the future that would also need to be carefully danced around in a similar fashion.
  • As a slightly less short-term workaround, one might be able to defer the formatting of the messages separately from the Block objects. For example, by accepting a reason-msg option, which would hold a message key or Message object. This would hide the issue similar to the above, by deferring the look up of the user language and the fetching/formatting of the message until it is displayed, assuming that by that time, the user object is initialised.

Ideally, the dependency on a language choice would be made explicit in the BlockManager by having MessageLocaliser be one of its method parameters (or constructor parameters). Then, when the user object tries to get the BlockManager, it is clear that it needs to decide on a language first.

Then you'd call wfMessage()->inLanguage($x) or $localiser->msg(), instead of wfMessage(), and can safely fetch and format messages at any time.

@Krinkle Thanks for the verbosity.

  • As a slightly less short-term workaround, one might be able to defer the formatting of the messages separately from the Block objects. For example, by accepting a reason-msg option, which would hold a message key or Message object. This would hide the issue similar to the above, by deferring the look up of the user language and the fetching/formatting of the message until it is displayed, assuming that by that time, the user object is initialised.

Filed as T227007.

Ideally, the dependency on a language choice would be made explicit in the BlockManager by having MessageLocaliser be one of its method parameters (or constructor parameters).

Thanks for the suggestion - hopefully we can remove the dependency as suggested above instead.

There's a fix in master: https://gerrit.wikimedia.org/r/#/c/mediawiki/core/+/519177/ It was tagged with T180050, which this task seems to duplicate (see above). Do you think we should backport that commit?

It'll roll out with the train tomorrow, but generally would've been something worth backporting I think.

@Krinkle Good to know for next time.

This problem seems to be fixed now, but the fix seems to be causing another error - T227901

Niharika closed this task as Resolved.Jul 16 2019, 5:00 PM
Niharika claimed this task.
mmodell changed the subtype of this task from "Task" to "Production Error".Aug 28 2019, 11:06 PM