Page MenuHomePhabricator

Wikimedia\Assert\ParameterAssertionException: Bad value for parameter $page: must represent an existing page (via RecentChange::notifyEdit)
Closed, ResolvedPublicPRODUCTION ERROR

Description

Error
labels.normalized_message
[{reqId}] {exception_url}   Wikimedia\Assert\ParameterAssertionException: Bad value for parameter $page: must represent an existing page
FrameLocationCall
from/srv/mediawiki/php-1.44.0-wmf.4/vendor/wikimedia/assert/src/Assert.php(72)
#0/srv/mediawiki/php-1.44.0-wmf.4/includes/recentchanges/RecentChange.php(771)Wikimedia\Assert\Assert::parameter(bool, string, string)
#1/srv/mediawiki/php-1.44.0-wmf.4/includes/recentchanges/ChangeTrackingEventIngress.php(108)RecentChange::notifyEdit(string, MediaWiki\Title\Title, bool, MediaWiki\User\User, string, int, string, bool, string, int, int, int, int, array, MediaWiki\Storage\EditResult)
#2/srv/mediawiki/php-1.44.0-wmf.4/includes/recentchanges/ChangeTrackingEventIngress.php(50)MediaWiki\RecentChanges\ChangeTrackingEventIngress->updateRecentChangesAfterPageUpdated(MediaWiki\Revision\RevisionStoreRecord, MediaWiki\Revision\RevisionStoreRecord, bool, int, array, MediaWiki\Storage\EditResult)
#3/srv/mediawiki/php-1.44.0-wmf.4/includes/DomainEvent/DomainEventDispatcher.php(139)MediaWiki\RecentChanges\ChangeTrackingEventIngress->afterPageUpdated(MediaWiki\Storage\PageUpdatedEvent, Wikimedia\Rdbms\LBFactoryMulti)
#4/srv/mediawiki/php-1.44.0-wmf.4/includes/DomainEvent/DomainEventDispatcher.php(123)MediaWiki\DomainEvent\DomainEventDispatcher->invoke(array, MediaWiki\Storage\PageUpdatedEvent, Wikimedia\Rdbms\LBFactoryMulti)
#5/srv/mediawiki/php-1.44.0-wmf.4/includes/deferred/MWCallableUpdate.php(52)MediaWiki\DomainEvent\DomainEventDispatcher->MediaWiki\DomainEvent\{closure}(string)
#6/srv/mediawiki/php-1.44.0-wmf.4/includes/deferred/DeferredUpdates.php(460)MediaWiki\Deferred\MWCallableUpdate->doUpdate()
#7/srv/mediawiki/php-1.44.0-wmf.4/includes/deferred/DeferredUpdates.php(204)MediaWiki\Deferred\DeferredUpdates::attemptUpdate(MediaWiki\Deferred\MWCallableUpdate)
#8/srv/mediawiki/php-1.44.0-wmf.4/includes/deferred/DeferredUpdates.php(291)MediaWiki\Deferred\DeferredUpdates::run(MediaWiki\Deferred\MWCallableUpdate)
#9/srv/mediawiki/php-1.44.0-wmf.4/includes/deferred/DeferredUpdatesScope.php(243)MediaWiki\Deferred\DeferredUpdates::MediaWiki\Deferred\{closure}(MediaWiki\Deferred\MWCallableUpdate, int)
#10/srv/mediawiki/php-1.44.0-wmf.4/includes/deferred/DeferredUpdatesScope.php(172)MediaWiki\Deferred\DeferredUpdatesScope->processStageQueue(int, int, Closure)
#11/srv/mediawiki/php-1.44.0-wmf.4/includes/deferred/DeferredUpdates.php(310)MediaWiki\Deferred\DeferredUpdatesScope->processUpdates(int, Closure)
#12/srv/mediawiki/php-1.44.0-wmf.4/includes/MediaWikiEntryPoint.php(674)MediaWiki\Deferred\DeferredUpdates::doUpdates()
#13/srv/mediawiki/php-1.44.0-wmf.4/includes/MediaWikiEntryPoint.php(496)MediaWiki\MediaWikiEntryPoint->restInPeace()
#14/srv/mediawiki/php-1.44.0-wmf.4/includes/MediaWikiEntryPoint.php(454)MediaWiki\MediaWikiEntryPoint->doPostOutputShutdown()
#15/srv/mediawiki/php-1.44.0-wmf.4/includes/MediaWikiEntryPoint.php(209)MediaWiki\MediaWikiEntryPoint->postOutputShutdown()
#16/srv/mediawiki/php-1.44.0-wmf.4/api.php(44)MediaWiki\MediaWikiEntryPoint->run()
#17/srv/mediawiki/w/api.php(3)require(string)
#18{main}
Impact
Notes

This has been happening for days at varying rates after T377229. It always involves DeferredUpdates, so probably the page gets deleted before the change notification code runs but that needs to be investigated.

Event Timeline

Samwalton9-WMF added subscribers: daniel, Samwalton9-WMF.

This has been happening for days at varying rates after T377229.

FYI @daniel

This isn't good, but the error rate is relatively low. Tagging MW-Interfaces-Team for tracking, since this is fallout from T376063: Introduce a system of events and listeners into MediaWiki core (FY24/25, WE5.2.3 and WE5.2.5).

I suspect that the issue is caused by replication lag or a race condition when a page is deleted immediately after an edit. If that is indeed that case, it should be fixed soon by T380536: RevisionRecord::getPage() should return an immutable ProperPageIdentity (though that patch is a bit risky itself).

daniel triaged this task as High priority.Nov 25 2024, 4:48 PM

Tagging as high, since it definitly needs fixing, though the impact isn't huge.

The patch that I hoped would fix this rode the train on the week of December 9th (1.44.0-wmf.6), but apparently didn't fix the issue. I'm confused about the fact that it did nothing. I would have expected the error to at least be triggered earlier, in the constructor of RevisionRecord. If the RevisionRecord was constructed on an existing page, and it's immutable, how can the page later not exist?...

Needs further investigation.

Note that the patch in question was reverted because it caused T381982: Fatal exception of type "Wikimedia\Assert\PreconditionException" when marking a page for translation

Looking at other errors in the requests that trigger this error indicate that this may be the consequence of something else failing... In all requests that I looked at, ParserCache is triggering a warning for "inconsistent revision ID", e.g. https://logstash.wikimedia.org/goto/386604c4622a5a49eea2b4823fe3e364 and https://logstash.wikimedia.org/goto/9f64b0643577d3708f452b3027e9ebf9. Many of the affected requests seem to be using pygmentize, but not all do: https://logstash.wikimedia.org/goto/31b977e276d74ba77b2f131b9a4e59b1.

The patch that I hoped would fix this rode the train on the week of December 9th (1.44.0-wmf.6), but apparently didn't fix the issue.

https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1094003 isn't listed in the wmf.6 pick-list, which makes sense because it was merged on 11th December and wmf.6 was cut on 3rd December; this patch hasn't been deployed to production yet.

https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1094003 isn't listed in the wmf.6 pick-list, which makes sense because it was merged on 11th December and wmf.6 was cut on 3rd December; this patch hasn't been deployed to production yet.

I see it merged on December 5th, I would have expected it to go on the train on December 10th - but I guess we just didn't do wmf.7.

Thanks for checking!

I'm trying to move a page on mediawiki.org and cannot do so because of this error. There are two errors:

[4330b8c2-4bd6-464c-9ba8-10505a64c749] /w/index.php?action=submit&title=Special:MovePage   Wikimedia\Assert\ParameterAssertionException: Bad value for parameter $page: must represent an existing page

followed by

[4330b8c2-4bd6-464c-9ba8-10505a64c749] /w/index.php?action=submit&title=Special:MovePage   MediaWiki\Revision\RevisionAccessException: Can't find revision 6968088

I'm trying to move https://www.mediawiki.org/wiki/Trust_and_Safety_Product/Team/Norms to https://www.mediawiki.org/wiki/Trust_and_Safety_Product/Team/Practices.

The trigger is different this time around, but it's another instance where we apparently try to instantiate a revision for a non-existing page. Probably something is getting out of whack due to the page move. It's triggered through Wikidata, so it doesn't show up in CI...

Stack trace:

from /srv/mediawiki/php-1.44.0-wmf.12/vendor/wikimedia/assert/src/Assert.php(72)
#0 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RevisionStoreRecord.php(74): Wikimedia\Assert\Assert::parameter(bool, string, string)
#1 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RevisionStore.php(1828): MediaWiki\Revision\RevisionStoreRecord->__construct(MediaWiki\Title\Title, MediaWiki\User\UserIdentityValue, MediaWiki\CommentStore\CommentStoreComment, stdClass, MediaWiki\Revision\RevisionSlots, bool)
#2 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RevisionStore.php(1630): MediaWiki\Revision\RevisionStore->newRevisionFromRowAndSlots(stdClass, MediaWiki\Revision\RevisionSlots, int, MediaWiki\Title\Title, bool)
#3 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RevisionStore.php(2367): MediaWiki\Revision\RevisionStore->newRevisionFromRow(stdClass, int, MediaWiki\Title\Title)
#4 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RevisionStore.php(2327): MediaWiki\Revision\RevisionStore->loadRevisionFromConds(Wikimedia\Rdbms\DBConnRef, array, int, MediaWiki\Title\Title, array)
#5 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RevisionStore.php(3049): MediaWiki\Revision\RevisionStore->newRevisionFromConds(array, int, MediaWiki\Title\Title, array)
#6 /srv/mediawiki/php-1.44.0-wmf.12/extensions/Wikibase/client/includes/ParserOutput/ClientParserOutputDataUpdater.php(212): MediaWiki\Revision\RevisionStore->getFirstRevision(MediaWiki\Title\Title)
#7 /srv/mediawiki/php-1.44.0-wmf.12/extensions/Wikibase/client/includes/Hooks/ParserOutputUpdateHookHandler.php(95): Wikibase\Client\ParserOutput\ClientParserOutputDataUpdater->updateFirstRevisionTimestampProperty(MediaWiki\Title\Title, Wikibase\Client\ParserOutput\ScopedParserOutputProvider)
#8 /srv/mediawiki/php-1.44.0-wmf.12/extensions/Wikibase/client/includes/Hooks/ParserOutputUpdateHookHandler.php(68): Wikibase\Client\Hooks\ParserOutputUpdateHookHandler->doContentAlterParserOutput(MediaWiki\Content\WikitextContent, MediaWiki\Title\Title, MediaWiki\Parser\ParserOutput)
#9 /srv/mediawiki/php-1.44.0-wmf.12/includes/HookContainer/HookContainer.php(159): Wikibase\Client\Hooks\ParserOutputUpdateHookHandler->onContentAlterParserOutput(MediaWiki\Content\WikitextContent, MediaWiki\Title\Title, MediaWiki\Parser\ParserOutput)
#10 /srv/mediawiki/php-1.44.0-wmf.12/includes/HookContainer/HookRunner.php(1231): MediaWiki\HookContainer\HookContainer->run(string, array)
#11 /srv/mediawiki/php-1.44.0-wmf.12/includes/content/ContentHandler.php(1713): MediaWiki\HookContainer\HookRunner->onContentAlterParserOutput(MediaWiki\Content\WikitextContent, MediaWiki\Title\Title, MediaWiki\Parser\ParserOutput)
#12 /srv/mediawiki/php-1.44.0-wmf.12/includes/content/Renderer/ContentRenderer.php(79): MediaWiki\Content\ContentHandler->getParserOutput(MediaWiki\Content\WikitextContent, MediaWiki\Content\Renderer\ContentParseParams)
#13 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RenderedRevision.php(264): MediaWiki\Content\Renderer\ContentRenderer->getParserOutput(MediaWiki\Content\WikitextContent, MediaWiki\Page\PageIdentityValue, MediaWiki\Revision\MutableRevisionRecord, MediaWiki\Parser\ParserOptions, array)
#14 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RenderedRevision.php(236): MediaWiki\Revision\RenderedRevision->getSlotParserOutputUncached(MediaWiki\Content\WikitextContent, array)
#15 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RevisionRenderer.php(239): MediaWiki\Revision\RenderedRevision->getSlotParserOutput(string, array)
#16 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RevisionRenderer.php(172): MediaWiki\Revision\RevisionRenderer->combineSlotOutput(MediaWiki\Revision\RenderedRevision, MediaWiki\Parser\ParserOptions, array)
#17 [internal function]: MediaWiki\Revision\RevisionRenderer->MediaWiki\Revision\{closure}(MediaWiki\Revision\RenderedRevision, array)
#18 /srv/mediawiki/php-1.44.0-wmf.12/includes/Revision/RenderedRevision.php(199): call_user_func(Closure, MediaWiki\Revision\RenderedRevision, array)
#19 /srv/mediawiki/php-1.44.0-wmf.12/extensions/TemplateData/includes/Hooks.php(116): MediaWiki\Revision\RenderedRevision->getRevisionParserOutput(array)
#20 /srv/mediawiki/php-1.44.0-wmf.12/includes/HookContainer/HookContainer.php(159): MediaWiki\Extension\TemplateData\Hooks->onMultiContentSave(MediaWiki\Revision\RenderedRevision, MediaWiki\User\User, MediaWiki\CommentStore\CommentStoreComment, int, MediaWiki\Storage\PageUpdateStatus)
#21 /srv/mediawiki/php-1.44.0-wmf.12/includes/HookContainer/HookRunner.php(2677): MediaWiki\HookContainer\HookContainer->run(string, array)
#22 /srv/mediawiki/php-1.44.0-wmf.12/includes/Storage/PageUpdater.php(901): MediaWiki\HookContainer\HookRunner->onMultiContentSave(MediaWiki\Revision\RenderedRevision, MediaWiki\User\User, MediaWiki\CommentStore\CommentStoreComment, int, MediaWiki\Storage\PageUpdateStatus)
#23 /srv/mediawiki/php-1.44.0-wmf.12/includes/page/MovePage.php(988): MediaWiki\Storage\PageUpdater->saveRevision(MediaWiki\CommentStore\CommentStoreComment)
#24 /srv/mediawiki/php-1.44.0-wmf.12/includes/page/MovePage.php(645): MediaWiki\Page\MovePage->moveToInternal(MediaWiki\User\User, MediaWiki\Title\Title, string, bool, array)
#25 /srv/mediawiki/php-1.44.0-wmf.12/includes/page/MovePage.php(493): MediaWiki\Page\MovePage->moveUnsafe(MediaWiki\User\User, string, bool, array)
#26 /srv/mediawiki/php-1.44.0-wmf.12/includes/specials/SpecialMovePage.php(800): MediaWiki\Page\MovePage->moveIfAllowed(MediaWiki\User\User, string, bool)
#27 /srv/mediawiki/php-1.44.0-wmf.12/includes/specials/SpecialMovePage.php(239): MediaWiki\Specials\SpecialMovePage->doSubmit()
#28 /srv/mediawiki/php-1.44.0-wmf.12/extensions/Translate/src/PageTranslation/MoveTranslatableBundleSpecialPage.php(163): MediaWiki\Specials\SpecialMovePage->execute(null)
#29 /srv/mediawiki/php-1.44.0-wmf.12/includes/specialpage/SpecialPage.php(729): MediaWiki\Extension\Translate\PageTranslation\MoveTranslatableBundleSpecialPage->execute(null)
#30 /srv/mediawiki/php-1.44.0-wmf.12/includes/specialpage/SpecialPageFactory.php(1738): MediaWiki\SpecialPage\SpecialPage->run(null)
#31 /srv/mediawiki/php-1.44.0-wmf.12/includes/actions/ActionEntryPoint.php(504): MediaWiki\SpecialPage\SpecialPageFactory->executePath(string, MediaWiki\Context\RequestContext)
#32 /srv/mediawiki/php-1.44.0-wmf.12/includes/actions/ActionEntryPoint.php(146): MediaWiki\Actions\ActionEntryPoint->performRequest()
#33 /srv/mediawiki/php-1.44.0-wmf.12/includes/MediaWikiEntryPoint.php(202): MediaWiki\Actions\ActionEntryPoint->execute()
#34 /srv/mediawiki/php-1.44.0-wmf.12/index.php(58): MediaWiki\MediaWikiEntryPoint->run()
#35 /srv/mediawiki/w/index.php(3): require(string)
#36 {main}
daniel raised the priority of this task from High to Unbreak Now!.

I'll try to look into this today. If I can't find it in time, we'll have to revert https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1105447.

EDIT: or https://gerrit.wikimedia.org/r/c/mediawiki/extensions/Wikibase/+/1105355

Analysis:

  • MovePage::moveToInternal calls PageUpdater::saveRevision() to create a new redirect page under the old title, after the original page has been moved.
  • PageUpdater triggers the MultiContentSave hook and passes it a RenderedRevision object representing the new redirect page
  • TemplateData's handler for this hook calls getRevisionParserOutput on the RenderedRevision. TemplateData's invokvement is probably not relevant, getRevisionParserOutput will get called sooner or later by something or other.
  • RenderedRevision ends up calling ContentRenderer::getParserOutput which calls ContentHandler::getParserOutput
  • ContentHandler triggers the ContentAlterParserOutput hook, passing it a Title object which it created by calling TitleFactory::newFromPageReference based on a PageReference representing the new redirect page. This PageReference was obtained from the RevisionRecord created by PageUpdater (see renderedRevision::getSlotParserOutputUncached). newFromPageReference () does not use a Title cache, but will inherit the page ID if the PageReference is a PageIdentity, which is the case here. Presumably, this ID is 0 at this point, sine the PageIdentifier object we are getting here was constructed before the page was created (to be confirmed).
  • Wikibase's ParserOutputUpdateHookHandler calls ClientParserOutputDataUpdater which calls RevisionStore::getFirstRevision, passing the Title object created by ContentHandler.
  • RevisionStore::getFirstRevision causes a database query for the oldest revision of the page. The query uses namespace and name, not the page ID! It seems likely that the page ID in the Title object at this point is either 0, instead of the newly created redirect (to be confirmed). However, the query should find the single newly created revision of the redirect page at this point (to be confirmed).
  • RevisionStore finds revision rows and tries to instantiate a RevisionStoreRecord for them, passing in the Title object that was provided to the getFirstRevision () call. This fails, because the Title object has page ID 0.

The root of the issue seems to be that the MultiContentSave hook is a pre-save hook. The revision can't be expected to exist at this point.

It's curious that getFirstrevision finds any revisions at all. It shouldn't, since the new redirect page hasn't been saved to the database at this point. Perhaps it's finding revisions of the moved page, due to replication lag? That's actually quite likely.

Actually, the relevant code in Wikibase was merged just last week. Perhaps that's what introduced the bug? https://gerrit.wikimedia.org/r/c/mediawiki/extensions/Wikibase/+/1105355

Pinging @SuzanneWood-WMDE and @seanleong-WMDE from and tagging MediaWiki-extensions-Wikibase-Client.

@daniel happy for that change to be reverted if it's causing an issue, we'll also look into it

@daniel happy for that change to be reverted if it's causing an issue, we'll also look into it

Thanks! Note that you patch may only be one of the contributing factors here. But it does look suspicious...

Looking at the code, it seems like you are trying to add the ID of the page's first revision to the ParserOutout. But the ParserOutput is generally created before the page is saved, so for a new page, there's n first revision yet. And on page moves, things may get very confusing, see above.

Change #1111658 had a related patch set uploaded (by Daniel Kinzler; author: Daniel Kinzler):

[mediawiki/core@master] RvisionStore: No first revision of non-existing page

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

Change #1111658 merged by jenkins-bot:

[mediawiki/core@master] RevisionStore: No first revision of non-existing page

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

Change #1111680 had a related patch set uploaded (by BPirkle; author: Daniel Kinzler):

[mediawiki/core@wmf/1.44.0-wmf.12] RevisionStore: No first revision of non-existing page

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

Change #1111680 merged by jenkins-bot:

[mediawiki/core@wmf/1.44.0-wmf.12] RevisionStore: No first revision of non-existing page

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

Mentioned in SAL (#wikimedia-operations) [2025-01-15T19:22:35Z] <brennen@deploy2002> Started scap sync-world: Backport for [[gerrit:1111680|RevisionStore: No first revision of non-existing page (T380677)]]

Mentioned in SAL (#wikimedia-operations) [2025-01-15T19:28:59Z] <brennen@deploy2002> bpirkle, brennen: Backport for [[gerrit:1111680|RevisionStore: No first revision of non-existing page (T380677)]] synced to the testservers (https://wikitech.wikimedia.org/wiki/Mwdebug)

Mentioned in SAL (#wikimedia-operations) [2025-01-15T19:39:36Z] <brennen@deploy2002> Finished scap sync-world: Backport for [[gerrit:1111680|RevisionStore: No first revision of non-existing page (T380677)]] (duration: 17m 00s)

@SuzanneWood-WMDE and @seanleong-WMDE the operational issue should be fixed by the backport of the work-around I made, but I think the code in Wikibase doesn't work as intended. See my comments on the patch.

I just moved the page without problems. Looks like this is fixed.

I also don't see this problem in logstash anymore. There's still an instance of the exception that gets triggered by an API request every now and then, but it seems like a symptom of a different problem, and its rare.

So I'm closing this as resolved.

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

[mediawiki/core@master] [POC] RevisionStore: Query by page_id when available

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

Aklapper renamed this task from Wikimedia\Assert\ParameterAssertionException: Bad value for parameter $page: must represent an existing page to Wikimedia\Assert\ParameterAssertionException: Bad value for parameter $page: must represent an existing page (via RecentChange::notifyEdit).Mar 27 2025, 10:38 AM

Change #1113455 merged by jenkins-bot:

[mediawiki/core@master] RevisionStore: Query by page_id when available

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