Fixed LogicException: Attempted to set 'alerts_unviewed

PASS

Well-known member
Affected version
2.2.1
First time I've ever seen this error. Probably some fluke thing. Only 1 error.

  • LogicException: Attempted to set 'alerts_unviewed' while a save was pending without forceSet
  • src/XF/Mvc/Entity/Entity.php:594
 
Stack trace
#0 src/XF/Mvc/Entity/Entity.php(567): XF\Mvc\Entity\Entity->set('alerts_unviewed', -1)
#1 src/XF/Repository/UserAlert.php(412): XF\Mvc\Entity\Entity->__set('alerts_unviewed', -1)
#2 src/XF/Db/AbstractAdapter.php(455): XF\Repository\UserAlert->XF\Repository\{closure}(Object(XF\Db\Mysqli\Adapter))
#3 src/XF/Db/AbstractAdapter.php(464): XF\Db\AbstractAdapter->executeTransaction(Object(Closure), 0)
#4 src/XF/Repository/UserAlert.php(415): XF\Db\AbstractAdapter->executeTransaction(Object(Closure), 1)
#5 src/XF/Repository/UserAlert.php(359): XF\Repository\UserAlert->markSpecificUserAlertsRead(Object(XF\Mvc\Entity\ArrayCollection), Object(NF\GiftUpgrades\XF\Entity\User), 1606413632)
#6 src/XF/Pub/Controller/Account.php(1305): XF\Repository\UserAlert->autoMarkUserAlertsRead(Object(XF\Mvc\Entity\ArrayCollection), Object(NF\GiftUpgrades\XF\Entity\User))
#7 src/XF/Mvc/Dispatcher.php(350): XF\Pub\Controller\Account->actionAlertsPopup(Object(XF\Mvc\ParameterBag))
#8 src/XF/Mvc/Dispatcher.php(257): XF\Mvc\Dispatcher->dispatchClass('XF:Account', 'AlertsPopup', Object(XF\Mvc\RouteMatch), Object(SV\ExpiringUserUpgrades\XF\Pub\Controller\Account), NULL)
#9 src/XF/Mvc/Dispatcher.php(113): XF\Mvc\Dispatcher->dispatchFromMatch(Object(XF\Mvc\RouteMatch), Object(SV\ExpiringUserUpgrades\XF\Pub\Controller\Account), NULL)
#10 src/XF/Mvc/Dispatcher.php(55): XF\Mvc\Dispatcher->dispatchLoop(Object(XF\Mvc\RouteMatch))
#11 src/XF/App.php(2300): XF\Mvc\Dispatcher->run()
#12 src/XF.php(465): XF\App->run()
#13 index.php(20): XF::runApp('XF\\Pub\\App')
#14 {main}

Never mind, looks like it might have to do with an addon. Sorry to have wasted your time.
 
This is actually a XenForo bug.

PHP:
protected function markSpecificUserAlertsRead(
   \XF\Mvc\Entity\AbstractCollection $alerts,
   \XF\Entity\User $user,
   int $readDate = null)
{
....
$db->executeTransaction(function() use ($db, $readDate, $user, $unreadAlertIds)
{
...

   $user->alerts_unviewed = ($user->alerts_unviewed - $alertsUnviewed);
   $user->alerts_unread = ($user->alerts_unread - count($unreadAlertIds));
   $user->save(true, false);
}, \XF\Db\AbstractAdapter::ALLOW_DEADLOCK_RERUN);
If the transaction is re-tried because of a deadlock triggered when updating the user record, then the user will be in a pending write state which will cause the error reported.

Somewhat related to this;
 
The actual error is because there is parts of the XenForo codebase which do updates to xf_user and then insert into xf_user_alert in the same transaction, while this code is updating xf_user_alert and then updating xf_user in a transaction.

This is an confused table locking order which will cause deadlocks, which then is masked by an error like this.

Ideally, XF should always kick alerts out of the content change transaction. But till then doing a select user_id from xf_user where user_id = ? for update to force xf_user/xf_user_alert lock ordering is a "simple" hack/fix.

This sadly also needs to apply when inserting an alert.
 
Last edited:
So far, I just had that one error. Guess the conditions have to be just right to trigger it. Good info, and well explained. Thx.
 
I got one also
Code:
Server error log

LogicException: Attempted to set 'alerts_unviewed' while a save was pending without forceSet src/XF/Mvc/Entity/Entity.php:594
Generated by: User Nov 30, 2020 at 6:55 AM

Stack trace
#0 src/XF/Mvc/Entity/Entity.php(567): XF\Mvc\Entity\Entity->set()
#1 src/XF/Repository/UserAlert.php(412): XF\Mvc\Entity\Entity->__set()
#2 src/XF/Db/AbstractAdapter.php(455): XF\Repository\UserAlert->XF\Repository\{closure}()
#3 src/XF/Db/AbstractAdapter.php(464): XF\Db\AbstractAdapter->executeTransaction()
#4 src/XF/Repository/UserAlert.php(415): XF\Db\AbstractAdapter->executeTransaction()
#5 src/XF/Repository/UserAlert.php(359): XF\Repository\UserAlert->markSpecificUserAlertsRead()
#6 src/XF/Pub/Controller/Account.php(1305): XF\Repository\UserAlert->autoMarkUserAlertsRead()
#7 src/XF/Mvc/Dispatcher.php(350): XF\Pub\Controller\Account->actionAlertsPopup()
#8 src/XF/Mvc/Dispatcher.php(257): XF\Mvc\Dispatcher->dispatchClass()
#9 src/XF/Mvc/Dispatcher.php(113): XF\Mvc\Dispatcher->dispatchFromMatch()
#10 src/XF/Mvc/Dispatcher.php(55): XF\Mvc\Dispatcher->dispatchLoop()
#11 src/XF/App.php(2300): XF\Mvc\Dispatcher->run()
#12 src/XF.php(465): XF\App->run()
#13 index.php(20): XF::runApp()
#14 {main}

Request state
array(4) {
  ["url"] => string(145) "/account/alerts-popup?_xfRequestUri=%2F&_xfWithData=1&_xfToken=1606690425%2C76f56dc7a303bcb1aa8c7e10f283bf35&_xfResponseType=json&_=1606690548608"
  ["referrer"] => string(21) "https://domain.com/"
  ["_GET"] => array(6) {
    ["/account/alerts-popup"] => string(0) ""
    ["_xfRequestUri"] => string(1) "/"
    ["_xfWithData"] => string(1) "1"
    ["_xfToken"] => string(43) "1606690425,76f56dc7a303bcb1aa8c7e10f283bf35"
    ["_xfResponseType"] => string(4) "json"
    ["_"] => string(13) "1606690548608"
  }
  ["_POST"] => array(0) {
  }
}
 
I got one also

Code:
LogicException: Attempted to set 'alerts_unviewed' while a save was pending without forceSet src/XF/Mvc/Entity/Entity.php:600 

Generated by: Γιώργος 82 Dec 18, 2022 at 12:09 PM 

Stack trace

#0 src/XF/Mvc/Entity/Entity.php(572): XF\Mvc\Entity\Entity->set('alerts_unviewed', -1)
#1 src/XF/Repository/UserAlert.php(414): XF\Mvc\Entity\Entity->__set('alerts_unviewed', -1)
#2 src/XF/Db/AbstractAdapter.php(457): XF\Repository\UserAlert->XF\Repository\{closure}(Object(XF\Db\Mysqli\Adapter))
#3 src/XF/Db/AbstractAdapter.php(466): XF\Db\AbstractAdapter->executeTransaction(Object(Closure), 0)
#4 src/XF/Repository/UserAlert.php(417): XF\Db\AbstractAdapter->executeTransaction(Object(Closure), 1)
#5 src/XF/Repository/UserAlert.php(361): XF\Repository\UserAlert->markSpecificUserAlertsRead(Object(XF\Mvc\Entity\ArrayCollection), Object(XF\Entity\User), 1671394168)
#6 src/XF/Pub/Controller/Account.php(1327): XF\Repository\UserAlert->autoMarkUserAlertsRead(Object(XF\Mvc\Entity\ArrayCollection), Object(XF\Entity\User))
#7 src/XF/Mvc/Dispatcher.php(352): XF\Pub\Controller\Account->actionAlertsPopup(Object(XF\Mvc\ParameterBag))
#8 src/XF/Mvc/Dispatcher.php(259): XF\Mvc\Dispatcher->dispatchClass('XF:Account', 'AlertsPopup', Object(XF\Mvc\RouteMatch), Object(ThemeHouse\Holidays\XF\Pub\Controller\Account), NULL)
#9 src/XF/Mvc/Dispatcher.php(115): XF\Mvc\Dispatcher->dispatchFromMatch(Object(XF\Mvc\RouteMatch), Object(ThemeHouse\Holidays\XF\Pub\Controller\Account), NULL)
#10 src/XF/Mvc/Dispatcher.php(57): XF\Mvc\Dispatcher->dispatchLoop(Object(XF\Mvc\RouteMatch))
#11 src/XF/App.php(2353): XF\Mvc\Dispatcher->run()
#12 src/XF.php(524): XF\App->run()
#13 index.php(20): XF::runApp('XF\\Pub\\App')
#14 {main}

Request state

array(4) {
  ["url"] => string(478) "/forums/account/alerts-popup?_xfRequestUri=%2Fforums%2Fthreads%2F%25CE%25A4%25CF%2583%25CE%25BF%25CF%2580%25CE%25B1%25CE%25BD%25CF%258C%25CF%2583%25CE%25BA%25CF%2585%25CE%25BB%25CE%25B1-%25CE%25BC%25CE%25B5-%25CE%25AC%25CE%25B3%25CF%2581%25CE%25B9%25CE%25B5%25CF%2582-%25CE%25B4%25CE%25B9%25CE%25B1%25CE%25B8%25CE%25AD%25CF%2583%25CE%25B5%25CE%25B9%25CF%2582.923%2Fpage-13&_xfWithData=1&_xfToken=1671394162%2Cf13b5b22bf3fc2537a5712255b1ab0b4&_xfResponseType=json&_=1671394163799"
  ["referrer"] => string(231) "https://www.hunterslife.gr/forums/threads/%CE%A4%CF%83%CE%BF%CF%80%CE%B1%CE%BD%CF%8C%CF%83%CE%BA%CF%85%CE%BB%CE%B1-%CE%BC%CE%B5-%CE%AC%CE%B3%CF%81%CE%B9%CE%B5%CF%82-%CE%B4%CE%B9%CE%B1%CE%B8%CE%AD%CF%83%CE%B5%CE%B9%CF%82.923/page-13"
  ["_GET"] => array(5) {
    ["_xfRequestUri"] => string(205) "/forums/threads/%CE%A4%CF%83%CE%BF%CF%80%CE%B1%CE%BD%CF%8C%CF%83%CE%BA%CF%85%CE%BB%CE%B1-%CE%BC%CE%B5-%CE%AC%CE%B3%CF%81%CE%B9%CE%B5%CF%82-%CE%B4%CE%B9%CE%B1%CE%B8%CE%AD%CF%83%CE%B5%CE%B9%CF%82.923/page-13"
    ["_xfWithData"] => string(1) "1"
    ["_xfToken"] => string(43) "1671394162,f13b5b22bf3fc2537a5712255b1ab0b4"
    ["_xfResponseType"] => string(4) "json"
    ["_"] => string(13) "1671394163799"
  }
  ["_POST"] => array(0) {
  }
}
 
  • LogicException: Attempted to set 'alerts_unviewed' while a save was pending without forceSet
  • src/XF/Mvc/Entity/Entity.php:605

#0 src/XF/Mvc/Entity/Entity.php(577): XF\Mvc\Entity\Entity->set('alerts_unviewed', -1)
#1 src/XF/Repository/UserAlert.php(414): XF\Mvc\Entity\Entity->__set('alerts_unviewed', -1)
#2 src/XF/Db/AbstractAdapter.php(457): XF\Repository\UserAlert->XF\Repository\{closure}(Object(XF\Db\Mysqli\Adapter))
#3 src/XF/Db/AbstractAdapter.php(466): XF\Db\AbstractAdapter->executeTransaction(Object(Closure), 0)
#4 src/XF/Repository/UserAlert.php(417): XF\Db\AbstractAdapter->executeTransaction(Object(Closure), 1)
#5 src/XF/Repository/UserAlert.php(361): XF\Repository\UserAlert->markSpecificUserAlertsRead(Object(XF\Mvc\Entity\ArrayCollection), Object(SV\SignupAbuseBlocking\XF\Entity\User), 1695278610)
#6 src/XF/Pub/Controller/Account.php(1345): XF\Repository\UserAlert->autoMarkUserAlertsRead(Object(XF\Mvc\Entity\ArrayCollection), Object(SV\SignupAbuseBlocking\XF\Entity\User))
#7 src/XF/Mvc/Dispatcher.php(352): XF\Pub\Controller\Account->actionAlertsPopup(Object(XF\Mvc\ParameterBag))
#8 src/XF/Mvc/Dispatcher.php(259): XF\Mvc\Dispatcher->dispatchClass('XF:Account', 'AlertsPopup', Object(XF\Mvc\RouteMatch), Object(SV\SignupAbuseBlocking\XF\Pub\Controller\Account), NULL)
#9 src/XF/Mvc/Dispatcher.php(115): XF\Mvc\Dispatcher->dispatchFromMatch(Object(XF\Mvc\RouteMatch), Object(SV\SignupAbuseBlocking\XF\Pub\Controller\Account), NULL)
#10 src/XF/Mvc/Dispatcher.php(57): XF\Mvc\Dispatcher->dispatchLoop(Object(XF\Mvc\RouteMatch))
#11 src/XF/App.php(2487): XF\Mvc\Dispatcher->run()
#12 src/XF.php(524): XF\App->run()
#13 index.php(20): XF::runApp('XF\\Pub\\App')
#14 {main}

XF 2.2.13
 
We've made some improvements here in 2.3.3 that should help to alleviate deadlocks. The user record is no longer updated via the entity system so this particular error should no longer occur.
 
Back
Top Bottom