Drupal et PostgreSQL : Error at offset 0 of … bytes drupal_includes_cache.inc

Publié le 12 February 2021

Il y a quelques jours j’ai dû copier un site Drupal de prod vers un autre serveur, pour en faire une préprod. Malgré une configuration qui semblait entièrement ISO, j’avais une plâtrée de messages d’erreur, du type :

Notice: unserialize(): Error at offset 0 of 1009 bytes in [...]drupal/includes/cache.inc on line 449
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Notice: unserialize(): Error at offset 0 of 1009 bytes in [...]drupal/includes/cache.inc on line 449
Notice: unserialize(): Error at offset 0 of 13 bytes in [...]drupal/includes/cache.inc on line 449
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Fatal error: Call to undefined function system_run_automated_cron() in [...]drupal/includes/common.inc on line 2784

Il m’a fallu du temps pour trouver comment corriger ce problème (d’ailleurs c’est même pas moi qui ai trouvé).

D’après internet, ces messages indiquent un problème dans la sérialisation des données.

Drupal a une drôle de façon de stocker ses données. Par exemple, si sur le serveur de base de données de prod je fais un :

SELECT variables FROM watchdog WHERE wid=10969;

ça me retournes :

a:2:{<200b><200b><200b><200b><200b><200b><200b>s:5:"@type";s:4:"page";s:6:"%title";s:52:"Titre chelou, j'ai pas le droit de mettre le vrai";}

Je ne sais pas pourquoi ils ont fait ça, mais Drupal utilise une base de données PostgreSQL pour ensuite stocker des données formatées en JSON.

Maintenant, si je fais la même requête sur le serveur de base de données de préprod, j’ai :

\x5469747265206368656C6F752C206A27616920706173206C652064726F6974206465206D6574747265206C652076726169

Le résultat est retourné au format hexadécimal. Si on le convertit en texte, on obtient bien la même chaîne que sur le serveur de prod. C’est juste le format de la donnée qui est différente.

En fait le serveur de base de données de prod avait été installé avec PostgreSQL 8, puis a ensuite été mis à jour vers PostgreSQL 9. Le serveur de prérpod, plus récent, a été installé directement en version 9. Sauf qu’entre les versions 8 et 9 de PostgreSQL, la gestion par défaut des données a changé. Ce qui me pose problème dans ce cas précis, c’est le bytea_output, qui est à escape en prod, mais à hex en préprod. Ca se corrige très simplement avec :

ALTER DATABASE nom_de_la_base SET bytea_output to 'escape';