During a recent piece of work, I enabled the Joomla debug mode. With debug activated, I found that certain pages within my site started giving me an error dump screen with the following error:
Exception
Serialization of 'Closure' is not allowed
.../libraries/joomla/cache/controller/callback.php:184
For ref, line 184 looks like this:
$this->cache->store(serialize($data), $id);
The error occurs when I view a page that shows a K2 category list. I don't believe that K2 is directly at fault here though because K2 has not had any version updates lately and debugging has worked just fine previously. It also works fine when debug mode is switched off, so it's something specific to debug.
Things that have changed on my site since the last time I used debug include the 3.7.0 and 3.7.1 updates, and various relatively minor extension updates.
I have done some debugging and used print_r()
to dump the contents of $data
into a file. It does indeed contain a number of closures within the callStacks
array. (I guess that the callStacks
array is only kept in debug mode, hence why the error only occurs with debug enabled?)
My dump file is 90MB in size, so I won't attach it here, but it shows that the closures which are triggering the error are at:
libraries/cms/component/helper.php:443
libraries/cms/plugin/helper.php:298
libraries/cms/menu/site.php:72
libraries/cms/library/helper.php:156
Looking at the code for all of these, I see that they all had similar changes made for the 3.7.0 release to wrap a DB query in a closure.
I would suggest that something needs to be corrected here in core. The obvious quick fix would be to remove the closures (maybe convert them into regular methods), but that wouldn't be good long-term, and would mean that we couldn't use closures anywhere. A better fix would be to sanitise the callStacks
array so that closures make it don't blow up when we try to serialize. Alternatively if serializing the stack for the cache is going to be a problem, maybe just remove callStacks
from the data being cached?
I haven't had time to set up an isolated system to find a minimum configuration to reproduce this issue, but it seems like it ought to be fairly easy to create a scenario that triggers it.
The page ought to render normally (but with the debug block at the foot)
Error page showing exception and line where it occurred.
Joomla 3.7.1 with a bunch of extensions installed and debug mode switched on.
Labels |
Added:
?
|
Damn, that was a quick response!
I think I can rule out a failed Joomla upgrade, as I did a "re-install all Joomla files" as part of the process of trying to work this out.
I did see the change to JCacheControllerCallback
(I dug into the recent git history), but the changes were relevant to the passed $callback
being a closure, whereas the crash is occurring because the returned result from $callback
contains closures.
In my case, this returned $result
is a massive TableK2Category
object, but any return value that contains closures will presumably have the same effect.
That's not going to be unique to 3.7 then or related to us now using Closures for some places where cache is used. Whomever is hooking into cache downstream is probably going to have to do some more screening of their data to ensure they aren't caching something that has a Closure attached to it.
This sounds like a K2 issue in that they are caching the call stack data somehow (Joomla core to the best of my knowledge doesn't cache a call stack anywhere and you'd have to be caching an object that includes something like a JLogEntry
instance or the database driver to get something that internally tracks a call stack for debugging purposes). There isn't a standardized object or structure to the data being processed so I don't think there is anything we can do to add post processing steps to our cache controllers.
Joomla core to the best of my knowledge doesn't cache a call stack anywhere
A quick search for callStacks
in Joomla core in my IDE gives 86 results, and the same search in the K2 codebase gives zero, so I don't think this is K2 storing the stacks; it's Joomla's debug mode.
Right. JLogEntry
and JDatabaseDriver
subclasses have call stacks for different purposes. But, Joomla core isn't caching anything that contains these objects. I don't know the structure of the TableK2Category
object, but if it's either a subclass of JTable
or has a parent that's something like that, it probably does have a JDatabaseDriver
object as a class property, and that is inherently causing the issue. I'd say that it's a bad idea for this object to be cached without implementing the Serializable
interface and limiting what data actually does get serialized out of it. We can implement Serializable
on JTable
, but we can't (nor should we) try to pre/post process a data object and manipulate what gets serialized at the cache layer.
Yes. I think we're getting to the nub of the issue now.
Yes, I can confirm -- the print_r()
output does show that TableK2Category
has a _db
property, and callStacks
is within that, so it looks like you're right on the button.
So... the answer is to implement Serializable
on JTable
so that it doesn't serialize its DB property.
Status | New | ⇒ | Discussion |
Category | ⇒ | com_cache |
Closed as we have a PR
Status | Discussion | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2017-05-23 16:20:51 |
Closed_By | ⇒ | brianteeman |
Reopening as PR for this issue has been abandoned.
Status | Closed | ⇒ | New |
Closed_Date | 2017-05-23 16:20:51 | ⇒ | |
Closed_By | brianteeman | ⇒ |
I guess nothing is going to happen here now and this should be closed. Not my call though
This should be closed. It really shouldnt be relevant for J4 and its such an old issue that even if someone has this error they will nebver find this issue
Status | New | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2022-08-23 19:37:03 |
Closed_By | ⇒ | zero-24 | |
Labels |
Added:
No Code Attached Yet
Removed: ? |
JCacheControllerCallback
was updated at 3.7 to support Closures (included in #10795). If you're getting this error, it points to a potentially failed upgrade or an extension overloading that class with a custom version.