How to fix Magento2 Page Cache error: “Unable to serialize value. Malformed UTF-8 characters”
If you’re using Magento’s Full Page Cache module, you may encounter that exception :
There has been an error processing your request
Unable to serialize value. Error: Malformed UTF-8 characters, possibly incorrectly encoded
Error log record number: 300877676469
If you open /var/report/300877676469, changes are you get a message like that :
{
"0": "Unable to serialize value. Error: Malformed UTF-8 characters, possibly incorrectly encoded",
"1": "
<pre>
#1 Magento\\Framework\\App\\PageCache\\Kernel->process(&Magento\\Framework\\App\\Response\\Http\\Interceptor#000000004d559138000000002f5a6de4#) called at [vendor/magento/module-page-cache/Model/Controller/Result/BuiltinPlugin.php:98]\n
#2 Magento\\PageCache\\Model\\Controller\\Result\\BuiltinPlugin->afterRenderResult(&Magento\\Framework\\View\\Result\\Page\\Interceptor#000000004d559a5b000000002f5a6de4#, &Magento\\Framework\\View\\Result\\Page\\Interceptor#000000004d559a5b000000002f5a6de4#, &Magento\\Framework\\App\\Response\\Http\\Interceptor#000000004d559138000000002f5a6de4#) called at [vendor/magento/framework/Interception/Interceptor.php:146]\n
#3 Magento\\Framework\\View\\Result\\Page\\Interceptor->Magento\\Framework\\Interception\\{closure}(&Magento\\Framework\\App\\Response\\Http\\Interceptor#000000004d559138000000002f5a6de4#) called at [vendor/magento/framework/Interception/Interceptor.php:153]\n
#4 Magento\\Framework\\View\\Result\\Page\\Interceptor->___callPlugins('renderResult', array(&Magento\\Framework\\App\\Response\\Http\\Interceptor#000000004d559138000000002f5a6de4#), array(array('result-messages', 'result-builtin-c...', 'result-varnish-c...'))) called at [generated/code/Magento/Framework/View/Result/Page/Interceptor.php:39]\n
#5 Magento\\Framework\\View\\Result\\Page\\Interceptor->renderResult(&Magento\\Framework\\App\\Response\\Http\\Interceptor#000000004d559138000000002f5a6de4#) called at [vendor/magento/framework/App/Http.php:141]\n
#6 Magento\\Framework\\App\\Http->launch() called at [vendor/magento/framework/App/Bootstrap.php:261]\n
#7 Magento\\Framework\\App\\Bootstrap->run(&Magento\\Framework\\App\\Http\\Interceptor#000000004d559136000000002f5a6de4#) called at [index.php:39]\n</pre>",
"url": "/my-super-page",
"script_name": "/index.php"
}
The error appears to come from a plugin from the Page Cache Magento module. Let edit the plugin a bit to make it log the problematic string (don’t forget to roll back the modification after the debug session) :
# \Magento\PageCache\Model\Controller\Result\BuiltinPlugin::afterRenderResult
# defined of vendor/magento/module-page-cache/Model/Controller/Result/BuiltinPlugin.php
# Line 96
try {
$this->kernel->process($response);
} catch (\Exception|\Error $e) {
file_put_contents("PROJECT/var/log/pagecache-" . time(), (string)$response);
throw $e;
}
You’ll get the HTML that was fetched from the cache logged to var/log/pagecache- followed by the current timestamp. Now we can use grep that log to print the lines that contains invalid UTF-8 characters :
$ grep -axv '.*' var/log/pagecache-1575036624
</script><meta name="description" content="Something went wrong with my descripti">
Seems the rendering of our meta description is responsible for the crash. Now let’s go to the code that prints that tag:
<?php substr($description, 0, 150); ?>
substr truncates the string regardless the encoding. Usually characters are encoded with a single byte, but UTF-8 character may be composed of two, three or even four bytes. Using substr here works only works if the 150th byte is not part of a multi-byte character, and won’t behave as expected (but won’t cause a crash) if the string contains multi-byte characters before the 150th byte.
Replacing substr by mb_substr solves the problem :
<?php mb_substr($description, 0, 150); ?>