Solved my own problem again. It transpires that I had renamed or re-parented my VpcDhcpOptionsAssociation resources in my script. pulumi then reflected that by creating the new VpcDhcpOptionsAssociation objects, then deleting the old ones. However deleting the old ones has the effect of clearing the DhcpOptions associated with each VPC. It seems like some resources should have deleteBeforeReplace set by default.