Yesterday our team faced problem saving system configuration in Magento 2 admin panel and they received the following exception “unable to unserialize value”.
1 exception(s): Exception #0 (InvalidArgumentException): Unable to unserialize value. Exception #0 (InvalidArgumentException): Unable to unserialize value.
After spending few hours our team came to know that this exception is related to MagentoFrameworkSerializeSerializerJson class. To be very specific the problem is in /vendor/magento/framework/Serialize/Serializer/Json.php file and there is a function unserialize($string) which gives you an exception if the string is already serialized.
The solution was to change the following file /vendor/magento/framework/Serialize/Serializer/Json.php especially the unserialize function.
Here is the original unserialize function -:
public function unserialize($string) { $result = json_decode($string, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new InvalidArgumentException('Unable to unserialize value.'); } return $result; }
Change the above function to the following -:
public function unserialize($string) { /* Added the following if clause to resolve the issue */ if($this->is_serialized($string)){ $string = $this->serialize($string); } $result = json_decode($string, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new InvalidArgumentException('Unable to unserialize value.'); } return $result; }
Also add the following is_serialized function in the same file /vendor/magento/framework/Serialize/Serializer/Json.php
function is_serialized($value, &$result = null) { // Bit of a give away this one if (!is_string($value)) { return false; } // Serialized false, return true. unserialize() returns false on an // invalid string or it could return false if the string is serialized // false, eliminate that possibility. if ($value === 'b:0;') { $result = false; return true; } $length = strlen($value); $end = ''; switch ($value[0]) { case 's': if ($value[$length - 2] !== '"') { return false; } case 'b': case 'i': case 'd': // This looks odd but it is quicker than isset()ing $end .= ';'; case 'a': case 'O': $end .= '}'; if ($value[1] !== ':') { return false; } switch ($value[2]) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: break; default: return false; } case 'N': $end .= ';'; if ($value[$length - 1] !== $end[0]) { return false; } break; default: return false; } if (($result = @unserialize($value)) === false) { $result = null; return false; } return true; }
Once the Json file was updated, we could manage to save the configuration without any issue. After saving the configuration we reverted the changes back to what it was and everything worked as expected there after.
Hope this article helped you in some way. Please leave us your comment and let us know what do you think? Thanks.