The solution is to change the way the database is migrated. I was dumping it, doing a search and replace and then loading the amended database. I have discovered this breaks serialization.
The solution which worked (and which I now believe is a best practice) is to dump and load the database unmodified. The use WPCLI to search and replace the links which handles serialization correctly. The syntax for so doing is
wp search-replace "https://old.url" "https://new.url"