Configuration import errors in Drupal 8

Overview

Depending on your site installation and configuration import workflow, you may occasionally see errors like this when importing configuration:

The import failed due for the following reasons: Entities exist of type (whatever). These entities need to be deleted before importing.

Needless to say, this isn't the most intuitive error message. Here's what's happening.

What the error means

Drupal stores a UUID with every configuration object on your site. Typically, there are two copies of each of these objects: one in active storage (i.e. the database), and one on disk (i.e. in config/default). Essentially, this error occurs when the copy of a config object in active storage has a UUID that doesn't match the UUID of the version on disk (i.e. the version being imported).

Why is it a problem if the UUIDs are different? Well, Drupal uses the UUID to track whether a field is new or not. For instance, imagine the scenario where you have a configuration entity (say a field), and you delete and recreate that entity with the exact same values as the original and then re-export your site's configuration. How is Drupal supposed to know that you actually deleted and recreated the field, if all of its properties are the same? The answer is the UUID, which will be different in the new field.

The final piece of the puzzle to understand here is that Drupal will not allow you to delete types of configuration like content types and vocabularies when content exists for those types.

So what's happening with the configuration import to cause the error is that Drupal is detecting the new UUID during import, and trying to delete and recreate the configuration entity accordingly, but its failing because of the existing content.

Common causes

Most commonly, you will see this error either when running configuration imports as part of a site install, or running configuration imports on a site with existing content. The second scenario is fairly easy to understand given the explanation above: Drupal won't let you delete configuration types with existing content. If you intended to delete and recreate the configuration in question, you will need to write an update hook to migrate existing content to the new config type instead of just relying on config-import to update the content and config. If you didn't intend to delete and recreate the config object, then you simply need to change the UUID of the config object on disk to match the UUID in the database.

The trickier source of this error is on site installs. This can occur when using an installation profile like Lightning that provides default content types and vocabularies. as Features, or creates them programmatically. The problem here is that when Drupal creates a field from scratch (rather than importing from existing config), it assigns it a random UUID. If you've also exported configuration for your site (i.e. to /config/default) and attempt to import that as part of the site install (as with Drush's --config-dir argument), Drupal will see that the UUIDs for all of these configuration objects have changed, and will attempt to delete and recreate them. Not only is this incredibly inefficient, but it can cause problems if you are also creating demo content as part of the install process.

The solution in this case is to use the method described here to install sites from existing configuration, rather than manually tweaking UUIDs, running config-import after install, or using Drush's --config-dir argument (which is deprecated in Drush 9 anyway).