Page MenuHomePhabricator

TypeError: MediaWiki\Parser\ParserOutput::getRevisionTimestamp(): Return value must be of type ?string, bool returned
Open, Needs TriagePublicPRODUCTION ERROR

Description

Error
  • service.version: 1.45.0-wmf.20
  • timestamp: 2025-09-24T20:31:03.889Z
  • labels.phpversion: 8.1.33
  • trace.id: 180fb2eacfbd70102568e3c3
  • Find trace.id in Logstash
labels.normalized_message
[{reqId}] {exception_url}   TypeError: MediaWiki\Parser\ParserOutput::getRevisionTimestamp(): Return value must be of type ?string, bool returned
FrameLocationCall
from/srv/mediawiki/php-1.45.0-wmf.20/includes/parser/ParserOutput.php(992)
#0/srv/mediawiki/php-1.45.0-wmf.20/includes/content/Renderer/ContentRenderer.php(89)MediaWiki\Parser\ParserOutput->getRevisionTimestamp()
#1/srv/mediawiki/php-1.45.0-wmf.20/includes/Revision/RenderedRevision.php(261)MediaWiki\Content\Renderer\ContentRenderer->getParserOutput(Flow\Content\BoardContent, MediaWiki\Page\PageIdentityValue, MediaWiki\Revision\RevisionStoreRecord, MediaWiki\Parser\ParserOptions, array)
#2/srv/mediawiki/php-1.45.0-wmf.20/includes/Revision/RenderedRevision.php(233)MediaWiki\Revision\RenderedRevision->getSlotParserOutputUncached(Flow\Content\BoardContent, array)
#3/srv/mediawiki/php-1.45.0-wmf.20/includes/Revision/RevisionRenderer.php(237)MediaWiki\Revision\RenderedRevision->getSlotParserOutput(string, array)
#4/srv/mediawiki/php-1.45.0-wmf.20/includes/Revision/RevisionRenderer.php(170)MediaWiki\Revision\RevisionRenderer->combineSlotOutput(MediaWiki\Revision\RenderedRevision, MediaWiki\Parser\ParserOptions, array)
#5/srv/mediawiki/php-1.45.0-wmf.20/includes/Revision/RenderedRevision.php(196)MediaWiki\Revision\RevisionRenderer->MediaWiki\Revision\{closure}(MediaWiki\Revision\RenderedRevision, array)
#6/srv/mediawiki/php-1.45.0-wmf.20/includes/Storage/DerivedPageDataUpdater.php(1424)MediaWiki\Revision\RenderedRevision->getRevisionParserOutput()
#7/srv/mediawiki/php-1.45.0-wmf.20/includes/Storage/DerivedPageDataUpdater.php(1904)MediaWiki\Storage\DerivedPageDataUpdater->getCanonicalParserOutput()
#8/srv/mediawiki/php-1.45.0-wmf.20/includes/Storage/DerivedPageDataUpdater.php(1796)MediaWiki\Storage\DerivedPageDataUpdater->doParserCacheUpdate()
#9/srv/mediawiki/php-1.45.0-wmf.20/includes/Storage/DerivedPageDataUpdater.php(1559)MediaWiki\Storage\DerivedPageDataUpdater->triggerParserCacheUpdate()
#10/srv/mediawiki/php-1.45.0-wmf.20/includes/Storage/PageUpdater.php(1722)MediaWiki\Storage\DerivedPageDataUpdater->doUpdates()
#11/srv/mediawiki/php-1.45.0-wmf.20/includes/libs/rdbms/database/Database.php(2334)MediaWiki\Storage\PageUpdater->MediaWiki\Storage\{closure}(Wikimedia\Rdbms\DatabaseMySQL, string)
#12/srv/mediawiki/php-1.45.0-wmf.20/includes/libs/rdbms/database/DBConnRef.php(127)Wikimedia\Rdbms\Database->doAtomicSection(string, Closure)
#13/srv/mediawiki/php-1.45.0-wmf.20/includes/libs/rdbms/database/DBConnRef.php(754)Wikimedia\Rdbms\DBConnRef->__call(string, array)
#14/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/AtomicSectionUpdate.php(41)Wikimedia\Rdbms\DBConnRef->doAtomicSection(string, Closure)
#15/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/DeferredUpdates.php(459)MediaWiki\Deferred\AtomicSectionUpdate->doUpdate()
#16/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/DeferredUpdates.php(201)MediaWiki\Deferred\DeferredUpdates::attemptUpdate(MediaWiki\Deferred\AtomicSectionUpdate)
#17/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/DeferredUpdates.php(288)MediaWiki\Deferred\DeferredUpdates::run(MediaWiki\Deferred\AtomicSectionUpdate)
#18/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/DeferredUpdatesScope.php(243)MediaWiki\Deferred\DeferredUpdates::MediaWiki\Deferred\{closure}(MediaWiki\Deferred\AtomicSectionUpdate, int)
#19/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/DeferredUpdatesScope.php(172)MediaWiki\Deferred\DeferredUpdatesScope->processStageQueue(int, int, Closure)
#20/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/DeferredUpdates.php(307)MediaWiki\Deferred\DeferredUpdatesScope->processUpdates(int, Closure)
#21/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/DeferredUpdates.php(373)MediaWiki\Deferred\DeferredUpdates::doUpdates(int)
#22/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/DeferredUpdates.php(156)MediaWiki\Deferred\DeferredUpdates::tryOpportunisticExecute()
#23/srv/mediawiki/php-1.45.0-wmf.20/includes/deferred/DeferredUpdates.php(179)MediaWiki\Deferred\DeferredUpdates::addUpdate(MediaWiki\Deferred\MWCallableUpdate, int)
#24/srv/mediawiki/php-1.45.0-wmf.20/includes/Storage/PageUpdater.php(994)MediaWiki\Deferred\DeferredUpdates::addCallableUpdate(Closure)
#25/srv/mediawiki/php-1.45.0-wmf.20/includes/page/WikiPage.php(1656)MediaWiki\Storage\PageUpdater->saveRevision(MediaWiki\CommentStore\CommentStoreComment, int)
#26/srv/mediawiki/php-1.45.0-wmf.20/extensions/Flow/includes/TalkpageManager.php(83)MediaWiki\Page\WikiPage->doUserEditContent(Flow\Content\BoardContent, MediaWiki\User\User, MediaWiki\CommentStore\CommentStoreComment, int)
#27/srv/mediawiki/php-1.45.0-wmf.20/extensions/Flow/includes/Import/TalkpageImportOperation.php(74)Flow\TalkpageManager->ensureFlowRevision(MediaWiki\Page\WikiPage, Flow\Model\Workflow)
#28/srv/mediawiki/php-1.45.0-wmf.20/extensions/Flow/includes/Import/Importer.php(114)Flow\Import\TalkpageImportOperation->import(Flow\Import\PageImportState)
#29/srv/mediawiki/php-1.45.0-wmf.20/extensions/Flow/includes/Import/Converter.php(215)Flow\Import\Importer->import(Flow\Import\LiquidThreadsApi\ImportSource, MediaWiki\Title\Title, MediaWiki\User\User, Flow\Import\SourceStore\FileImportSourceStore)
#30/srv/mediawiki/php-1.45.0-wmf.20/extensions/Flow/includes/Import/Converter.php(157)Flow\Import\Converter->doConversion(MediaWiki\Title\Title, null)
#31/srv/mediawiki/php-1.45.0-wmf.20/extensions/Flow/includes/Import/Converter.php(113)Flow\Import\Converter->convert(MediaWiki\Title\Title, bool, bool)
#32/srv/mediawiki/php-1.45.0-wmf.20/extensions/Flow/maintenance/convertAllLqtPages.php(111)Flow\Import\Converter->convertAll(AppendIterator, bool, bool)
#33/srv/mediawiki/php-1.45.0-wmf.20/maintenance/includes/MaintenanceRunner.php(696)Flow\Maintenance\ConvertAllLqtPages->execute()
#34/srv/mediawiki/php-1.45.0-wmf.20/maintenance/run.php(53)MediaWiki\Maintenance\MaintenanceRunner->run()
#35/srv/mediawiki/multiversion/MWScript.php(221)require_once(string)
#36{main}
Impact
Notes

Looks like it's triggered during MWScript exection, happened 8 times around 6PM CET Sept 24th, and 1 time on Sept 19th.

Event Timeline

Pppery subscribed.

I don't see how this could be Flow's fault; all Flow does is use a standard (albeit deprecated) core UI to make an edit.

The errors were at least triggered by our maintenance script runs.

Without being very familiar with Flow, and just from a cursory glance, there are a few places that get a timestamp via wfTimestamp (which returns false if the input is wrongly formed) that may not check the timestamp is a string before using it...

Usages: https://codesearch.wmcloud.org/search/?q=wfTimestamp%5C%28&files=&excludeFiles=&repos=Extension%3AFlow

Oh, right. Tracing the call stack,

		$parserOutput = $contentHandler->getParserOutput( $content, $cpoParams );
[...]
		if ( $parserOutput->getRevisionTimestamp() === null && $revTimestamp !== null ) {

(from https://github.com/wikimedia/mediawiki/blob/master/includes/content/ContentHandler.php)

			$this->fillParserOutput(
				$content,
				$cpoParams,
				$po
			);

From https://github.com/wikimedia/mediawiki-extensions-Flow/blob/master/includes/Content/BoardContentHandler.php

		if ( $revId === null ) {
			$wikiPage = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title );
			$timestamp = $wikiPage->getTimestamp();
		} else {
			$timestamp = MediaWikiServices::getInstance()->getRevisionLookup()
				->getTimestampFromId( $revId );
		}
		$output->setTimestamp( $timestamp );

Where setTimestamp is a deprecated alias for setRevisionTimestamp

You can see from Line 1 of the call stack that $revId almost certainly isn't null (if it were then null would have been passed there rather than a revisionRecord), so we call getTimestampFromId

	 * @return string|false False if not found
	 */
	public function getTimestampFromId( $id, $flags = 0 ) {

That's probably where the false is coming from, and that seems to be reading from a replica database. So looks like another database replication issue. Sigh.